|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
Patch bug64450.patch for *General Issues Bug #64450Patch version 2013-03-21 20:00 UTC Return to Bug #64450 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions:Developer: ab@php.net
diff --git a/ext/standard/php_rand.h b/ext/standard/php_rand.h
index e831f32..cc54702 100644
--- a/ext/standard/php_rand.h
+++ b/ext/standard/php_rand.h
@@ -43,6 +43,10 @@
#define RAND_RANGE(__n, __min, __max, __tmax) \
(__n) = (__min) + (long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
+#define RAND_RANGE_DOUBLE(__n, __min, __max, __tmax) \
+ (__n) = (__min) + ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0))
+
+
/* MT Rand */
#define PHP_MT_RAND_MAX ((long) (0x7FFFFFFF)) /* (1<<31) - 1 */
diff --git a/ext/standard/rand.c b/ext/standard/rand.c
index 5f55a41..36938c0 100644
--- a/ext/standard/rand.c
+++ b/ext/standard/rand.c
@@ -310,16 +310,15 @@ PHP_FUNCTION(rand)
Returns a random number from Mersenne Twister */
PHP_FUNCTION(mt_rand)
{
- long min;
- long max;
- long number;
+ double min, max, number_one;
+ long number_two;
int argc = ZEND_NUM_ARGS();
if (argc != 0) {
- if (zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
+ if (zend_parse_parameters(argc TSRMLS_CC, "dd", &min, &max) == FAILURE) {
return;
} else if (max < min) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%.0f) is smaller than min(%.0f)", max, min);
RETURN_FALSE;
}
}
@@ -328,20 +327,28 @@ PHP_FUNCTION(mt_rand)
php_mt_srand(GENERATE_SEED() TSRMLS_CC);
}
- /*
- * Melo: hmms.. randomMT() returns 32 random bits...
- * Yet, the previous php_rand only returns 31 at most.
- * So I put a right shift to loose the lsb. It *seems*
- * better than clearing the msb.
- * Update:
- * I talked with Cokus via email and it won't ruin the algorithm
- */
- number = (long) (php_mt_rand(TSRMLS_C) >> 1);
if (argc == 2) {
- RAND_RANGE(number, min, max, PHP_MT_RAND_MAX);
+ /* process the potentially overflowing variant*/
+ number_one = (double) (php_mt_rand(TSRMLS_C) >> 1);
+ RAND_RANGE_DOUBLE(number_one, min, max, PHP_MT_RAND_MAX);
+ if (number_one >= 0 && number_one <= LONG_MAX || number_one < 0 && number_one >= (-LONG_MAX-1)) {
+ RETURN_LONG((long)floor(number_one));
+ } else {
+ RETURN_DOUBLE(floor(number_one));
+ }
+ } else {
+ /*
+ * Melo: hmms.. randomMT() returns 32 random bits...
+ * Yet, the previous php_rand only returns 31 at most.
+ * So I put a right shift to loose the lsb. It *seems*
+ * better than clearing the msb.
+ * Update:
+ * I talked with Cokus via email and it won't ruin the algorithm
+ */
+ number_two = (long) (php_mt_rand(TSRMLS_C) >> 1);
+ RETURN_LONG(number_two);
}
- RETURN_LONG(number);
}
/* }}} */
--- /dev/null Thu Mar 21 20:59:11 2013
+++ ext/standard/tests/general_functions/bug64450.phpt Thu Mar 21 14:19:45 2013
@@ -0,0 +1,61 @@
+--TEST--
+Bug #64450 (mt_rand causes overflow within certain max value).
+--FILE--
+<?php
+ echo "var 1\n";
+ $min = 0;
+ $max = pow(10, 12);
+ $rand = mt_rand($min, $max);
+ var_dump($min, $max, $rand, $rand >= $min, $max >= $rand);
+
+ echo "var 2\n";
+ $min = 0;
+ $max = pow(10, 13);
+ $rand = mt_rand($min, $max);
+ var_dump($min, $max, $rand, $rand >= $min, $max >= $rand);
+
+ /* this should be always in the int range */
+ echo "var 3\n";
+ $min = 0;
+ $max = PHP_INT_MAX;
+ $rand = mt_rand($min, $max);
+ var_dump($min, $max, $rand, $rand >= $min, $max >= $rand);
+
+ echo "var 4\n";
+ $min = 0;
+ $max = PHP_INT_MAX+1;
+ $rand = mt_rand($min, $max);
+ var_dump($min, $max, $rand, $rand >= $min, $max >= $rand);
+
+ echo "var 5\n";
+ var_dump(mt_rand());
+?>
+==DONE==
+--EXPECTF--
+var 1
+int(0)
+%s(1000000000000)
+%s(%d)
+bool(true)
+bool(true)
+var 2
+int(0)
+%s(10000000000000)
+%s(%d)
+bool(true)
+bool(true)
+var 3
+int(0)
+int(%d)
+int(%d)
+bool(true)
+bool(true)
+var 4
+int(0)
+%s(%d)
+%s(%d)
+bool(true)
+bool(true)
+var 5
+int(%d)
+==DONE==
|
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Nov 02 03:00:01 2025 UTC |