1
0
mirror of https://github.com/php/php-src.git synced 2026-04-26 09:28:21 +02:00

Fix byte expansion in rand_rangeXX() (#9056)

* Fix shift in rand_range??()

The last generated size is in bytes, whereas the shift is in bits. Multiple the
generated size by 8 to correctly handle each byte once.

* Correctly handle user engines returning less than 4 bytes in rand_rangeXX()

We need to loop until we accumulate sufficient bytes, instead of just checking
once. The version in the rejection loop was already correct.

* Clean up some repetition in rand_rangeXX()
This commit is contained in:
Tim Düsterhus
2022-07-20 17:33:10 +02:00
committed by GitHub
parent 998ede7123
commit 804c3fc821
2 changed files with 40 additions and 32 deletions
+20 -32
View File
@@ -88,19 +88,16 @@ static inline uint32_t rand_range32(const php_random_algo *algo, php_random_stat
size_t total_size = 0;
uint32_t count = 0;
result = algo->generate(status);
total_size = status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
if (total_size < sizeof(uint32_t)) {
result = 0;
total_size = 0;
do {
r = algo->generate(status);
result = (result << status->last_generated_size) | r;
result = (result << (8 * status->last_generated_size)) | r;
total_size += status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
}
} while (total_size < sizeof(uint32_t));
/* Special case where no modulus is required */
if (UNEXPECTED(umax == UINT32_MAX)) {
@@ -126,19 +123,16 @@ static inline uint32_t rand_range32(const php_random_algo *algo, php_random_stat
return 0;
}
result = algo->generate(status);
total_size = status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
while (total_size < sizeof(uint32_t)) {
result = 0;
total_size = 0;
do {
r = algo->generate(status);
result = (result << status->last_generated_size) | r;
result = (result << (8 * status->last_generated_size)) | r;
total_size += status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
}
} while (total_size < sizeof(uint32_t));
}
return result % umax;
@@ -150,19 +144,16 @@ static inline uint64_t rand_range64(const php_random_algo *algo, php_random_stat
size_t total_size = 0;
uint32_t count = 0;
result = algo->generate(status);
total_size = status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
if (total_size < sizeof(uint64_t)) {
result = 0;
total_size = 0;
do {
r = algo->generate(status);
result = (result << status->last_generated_size) | r;
result = (result << (8 * status->last_generated_size)) | r;
total_size += status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
}
} while (total_size < sizeof(uint64_t));
/* Special case where no modulus is required */
if (UNEXPECTED(umax == UINT64_MAX)) {
@@ -188,19 +179,16 @@ static inline uint64_t rand_range64(const php_random_algo *algo, php_random_stat
return 0;
}
result = algo->generate(status);
total_size = status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
while (total_size < sizeof(uint64_t)) {
result = 0;
total_size = 0;
do {
r = algo->generate(status);
result = (result << status->last_generated_size) | r;
result = (result << (8 * status->last_generated_size)) | r;
total_size += status->last_generated_size;
if (status->last_unsafe) {
return 0;
}
}
} while (total_size < sizeof(uint64_t));
}
return result % umax;
@@ -0,0 +1,20 @@
--TEST--
Random: Randomizer: User Engine results are correctly expanded for getInt()
--FILE--
<?php
$randomizer = new \Random\Randomizer (
new class () implements \Random\Engine
{
public function generate(): string
{
return "\x01";
}
}
);
var_dump(bin2hex(pack('V', $randomizer->getInt(0, 0xFFFFFF))));
?>
--EXPECT--
string(8) "01010100"