From 1e1cbe73a690f280c294a074c3eb73435da47b06 Mon Sep 17 00:00:00 2001 From: denixport Date: Sun, 15 Dec 2013 00:32:18 +0400 Subject: [PATCH 1/4] fix Rand::getInteger() range overflow issue --- library/Zend/Math/Rand.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/library/Zend/Math/Rand.php b/library/Zend/Math/Rand.php index 95b71cde824..c1315bb464f 100644 --- a/library/Zend/Math/Rand.php +++ b/library/Zend/Math/Rand.php @@ -130,13 +130,21 @@ public static function getInteger($min, $max, $strong = false) 'The supplied range is too great to generate' ); } - $log = log($range, 2); - $bytes = (int) ($log / 8) + 1; - $bits = (int) $log + 1; - $filter = (int) (1 << $bits) - 1; + + // calculate number of bits required to store range on this machine + $r = $range; + $bits = 0; + while ($r >>= 1) { + $bits++; + } + + $bits = (int) max($bits, 1); + $bytes = (int) max(ceil($bits / 8), 1); + $filter = (int) ((1 << $bits) - 1); + do { - $rnd = hexdec(bin2hex(self::getBytes($bytes, $strong))); - $rnd = $rnd & $filter; + $rnd = hexdec(bin2hex(self::getBytes($bytes, $strong))); + $rnd &= $filter; } while ($rnd > $range); return ($min + $rnd); From bfb840c3654bc1a48b7c7416372fee6ea6621011 Mon Sep 17 00:00:00 2001 From: denixport Date: Sun, 15 Dec 2013 00:33:33 +0400 Subject: [PATCH 2/4] test for Rand::getInteger() range overflow issue --- tests/ZendTest/Math/RandTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/ZendTest/Math/RandTest.php b/tests/ZendTest/Math/RandTest.php index 86192b41569..9be4cd8f010 100644 --- a/tests/ZendTest/Math/RandTest.php +++ b/tests/ZendTest/Math/RandTest.php @@ -98,6 +98,16 @@ public function testIntegerRangeFail() $rand = Rand::getInteger(100, 0); } + public function testIntegerRangeOverflow() + { + $x = Rand::getInteger(0, PHP_INT_MAX); + for ($i = 0; $i < 5; $i++) { + $x ^= Rand::getInteger(0, PHP_INT_MAX); + } + + $this->assertFalse($x === 0); + } + public function testRandFloat() { for ($length = 1; $length < 512; $length++) { From cc119941ed751b05c86455542ffd932c8f888bfe Mon Sep 17 00:00:00 2001 From: denixport Date: Fri, 20 Dec 2013 16:53:24 +0400 Subject: [PATCH 3/4] use static:: ; improved test --- library/Zend/Math/Rand.php | 2 +- tests/ZendTest/Math/RandTest.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/Zend/Math/Rand.php b/library/Zend/Math/Rand.php index c1315bb464f..7b3fb0f2a19 100644 --- a/library/Zend/Math/Rand.php +++ b/library/Zend/Math/Rand.php @@ -143,7 +143,7 @@ public static function getInteger($min, $max, $strong = false) $filter = (int) ((1 << $bits) - 1); do { - $rnd = hexdec(bin2hex(self::getBytes($bytes, $strong))); + $rnd = hexdec(bin2hex(static::getBytes($bytes, $strong))); $rnd &= $filter; } while ($rnd > $range); diff --git a/tests/ZendTest/Math/RandTest.php b/tests/ZendTest/Math/RandTest.php index 9be4cd8f010..b1e132bf8ca 100644 --- a/tests/ZendTest/Math/RandTest.php +++ b/tests/ZendTest/Math/RandTest.php @@ -100,12 +100,13 @@ public function testIntegerRangeFail() public function testIntegerRangeOverflow() { - $x = Rand::getInteger(0, PHP_INT_MAX); - for ($i = 0; $i < 5; $i++) { - $x ^= Rand::getInteger(0, PHP_INT_MAX); + $values = array(); + $cycles = 100; + for ($i = 0; $i < $cycles; $i++) { + $values[$i] = Rand::getInteger(0, PHP_INT_MAX); } - $this->assertFalse($x === 0); + $this->assertFalse(array_unique($values) === 1); } public function testRandFloat() From 4a5a7df5b6721b98a3346fffcad4fbda32203955 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 5 Mar 2014 17:56:24 +0100 Subject: [PATCH 4/4] Improved the unit test for PHP_INT_MAX fix --- tests/ZendTest/Math/RandTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ZendTest/Math/RandTest.php b/tests/ZendTest/Math/RandTest.php index b1e132bf8ca..b2ce3cb17b0 100644 --- a/tests/ZendTest/Math/RandTest.php +++ b/tests/ZendTest/Math/RandTest.php @@ -100,13 +100,13 @@ public function testIntegerRangeFail() public function testIntegerRangeOverflow() { - $values = array(); + $values = 0; $cycles = 100; for ($i = 0; $i < $cycles; $i++) { - $values[$i] = Rand::getInteger(0, PHP_INT_MAX); + $values += Rand::getInteger(0, PHP_INT_MAX); } - $this->assertFalse(array_unique($values) === 1); + $this->assertFalse($values === 0); } public function testRandFloat()