diff --git a/NEWS b/NEWS index fcf4383f8fb0..afe853c2afa2 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,10 @@ PHP NEWS . Fixed bug GH-9818 (Initialize run time cache in PDO methods). (Florian Sowade) +- Random: + . Fixed bug GH-9839 (Pre-PHP 8.2 output compatibility for non-mt_rand() + functions for MT_RAND_PHP). (timwolla) + 27 Oct 2022, PHP 8.2.0RC5 - CLI: diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index 227c1ac02540..87f96be70abd 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -162,23 +162,7 @@ static uint64_t generate(php_random_status *status) static zend_long range(php_random_status *status, zend_long min, zend_long max) { - php_random_status_state_mt19937 *s = status->state; - - if (s->mode == MT_RAND_MT19937) { - return php_random_range(&php_random_algo_mt19937, status, min, max); - } - - /* Legacy mode deliberately not inside php_mt_rand_range() - * to prevent other functions being affected */ - - uint64_t r = php_random_algo_mt19937.generate(status) >> 1; - - /* This is an inlined version of the RAND_RANGE_BADSCALING macro that does not invoke UB when encountering - * (max - min) > ZEND_LONG_MAX. - */ - zend_ulong offset = (double) ( (double) max - min + 1.0) * (r / (PHP_MT_RAND_MAX + 1.0)); - - return (zend_long) (offset + min); + return php_random_range(&php_random_algo_mt19937, status, min, max); } static bool serialize(php_random_status *status, HashTable *data) diff --git a/ext/random/random.c b/ext/random/random.c index 13f1c94c3acf..161eb8e68520 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -449,7 +449,21 @@ PHPAPI zend_long php_mt_rand_range(zend_long min, zend_long max) * rand() allows min > max, mt_rand does not */ PHPAPI zend_long php_mt_rand_common(zend_long min, zend_long max) { - return php_mt_rand_range(min, max); + php_random_status *status = php_random_default_status(); + php_random_status_state_mt19937 *s = status->state; + + if (s->mode == MT_RAND_MT19937) { + return php_mt_rand_range(min, max); + } + + uint64_t r = php_random_algo_mt19937.generate(php_random_default_status()) >> 1; + + /* This is an inlined version of the RAND_RANGE_BADSCALING macro that does not invoke UB when encountering + * (max - min) > ZEND_LONG_MAX. + */ + zend_ulong offset = (double) ( (double) max - min + 1.0) * (r / (PHP_MT_RAND_MAX + 1.0)); + + return (zend_long) (offset + min); } /* }}} */ diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 0e3d90120b6f..391cc16cc74d 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -126,7 +126,22 @@ PHP_METHOD(Random_Randomizer, getInt) RETURN_THROWS(); } - result = randomizer->algo->range(randomizer->status, min, max); + if (UNEXPECTED( + randomizer->algo->range == php_random_algo_mt19937.range + && ((php_random_status_state_mt19937 *) randomizer->status->state)->mode != MT_RAND_MT19937 + )) { + uint64_t r = php_random_algo_mt19937.generate(randomizer->status) >> 1; + + /* This is an inlined version of the RAND_RANGE_BADSCALING macro that does not invoke UB when encountering + * (max - min) > ZEND_LONG_MAX. + */ + zend_ulong offset = (double) ( (double) max - min + 1.0) * (r / (PHP_MT_RAND_MAX + 1.0)); + + result = (zend_long) (offset + min); + } else { + result = randomizer->algo->range(randomizer->status, min, max); + } + if (EG(exception)) { RETURN_THROWS(); } diff --git a/ext/random/tests/01_functions/array_rand_mt_rand_php.phpt b/ext/random/tests/01_functions/array_rand_mt_rand_php.phpt new file mode 100644 index 000000000000..01a4e3ff5dfc --- /dev/null +++ b/ext/random/tests/01_functions/array_rand_mt_rand_php.phpt @@ -0,0 +1,32 @@ +--TEST-- +array_rand() is not affected by MT_RAND_PHP as with PHP < 8.2 +--FILE-- + +--EXPECTF-- +string(11) "found key 0" +string(11) "found key 1" +string(11) "found key 0" +string(3) "foo" +string(3) "bar" +string(3) "foo"