From e7265ff5775b210757b32a7127b2fdb6dab23f97 Mon Sep 17 00:00:00 2001 From: Anthony Ferrara Date: Tue, 17 Jan 2012 20:19:28 -0500 Subject: [PATCH] Fix bug with very large ranges --- lib/CryptLib/Random/Generator.php | 13 +++++++++---- test/Unit/Random/GeneratorTest.php | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/CryptLib/Random/Generator.php b/lib/CryptLib/Random/Generator.php index 2dff2cd..f40f6b7 100644 --- a/lib/CryptLib/Random/Generator.php +++ b/lib/CryptLib/Random/Generator.php @@ -94,14 +94,19 @@ public function generateInt($min = 0, $max = PHP_INT_MAX) { $range = $max - $min; if ($range == 0) { return $max; - } elseif ($range > PHP_INT_MAX) { - // This works, because PHP will auto-convert it to a float at this point + } elseif ($range > PHP_INT_MAX || is_float($range)) { + /** + * This works, because PHP will auto-convert it to a float at this point, + * But on 64 bit systems, the float won't have enough precision to + * actually store the difference, so we need to check if it's a float + * and hence auto-converted... + */ throw new \RangeException( 'The supplied range is too great to generate' ); } - $bits = ceil(log($range, 2)); - $bytes = max(ceil($bits / 8), 1); + $bits = (int) ceil(log($range, 2)); + $bytes = (int) max(ceil($bits / 8), 1); $mask = (int) (pow(2, $bits) - 1); /** * The mask is a better way of dropping unused bits. Basically what it does diff --git a/test/Unit/Random/GeneratorTest.php b/test/Unit/Random/GeneratorTest.php index 4707526..a4cf21c 100644 --- a/test/Unit/Random/GeneratorTest.php +++ b/test/Unit/Random/GeneratorTest.php @@ -167,6 +167,20 @@ public function testGenerateIntFail() { $n = $this->generator->generateInt(-1, PHP_INT_MAX); } + /** + * @covers CryptLib\Random\Generator::generateInt + */ + public function testGenerateIntLargeTest() { + $bits = 30; + $expected = 50529027; + if (PHP_INT_MAX > 4000000000) { + $bits = 56; + $expected = 1693273676973062; + } + $n = $this->generator->generateInt(0, pow(2, $bits)); + $this->assertEquals($expected, $n); + } + /** * @covers CryptLib\Random\Generator::generateString * @dataProvider provideGenerateStringTest