![]() |
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 14:03 UTC Return to Bug #64450 | Download this patchThis patch is obsolete Obsoleted by patches: Patch Revisions:Developer: ab@php.netdiff --git a/ext/standard/php_rand.h b/ext/standard/php_rand.h index e831f32..bdeaed1 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) + ( (double) (__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..f716bc6 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 <= LONG_MAX) { + 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 14:20:31 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== |
![]() All rights reserved. |
Last updated: Mon Apr 28 15:01:32 2025 UTC |