mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00

* Use `php_random_bytes_throw()` in Secure engine's generate() This exposes the underlying exception, improving debugging: Fatal error: Uncaught Exception: Cannot open source device in php-src/test.php:5 Stack trace: #0 php-src/test.php(5): Random\Engine\Secure->generate() #1 {main} Next RuntimeException: Random number generation failed in php-src/test.php:5 Stack trace: #0 php-src/test.php(5): Random\Engine\Secure->generate() #1 {main} thrown in php-src/test.php on line 5 * Use `php_random_int_throw()` in Secure engine's range() This exposes the underlying exception, improving debugging: Exception: Cannot open source device in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getInt(1, 3) #1 {main} Next RuntimeException: Random number generation failed in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getInt(1, 3) #1 {main} * Throw exception when a user engine returns an empty string This improves debugging, because the actual reason for the failure is available as a previous Exception: DomainException: The returned string must not be empty in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getBytes(123) #1 {main} Next RuntimeException: Random number generation failed in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getBytes(123) #1 {main} * Throw exception when the range selector fails to get acceptable numbers in 50 attempts This improves debugging, because the actual reason for the failure is available as a previous Exception: RuntimeException: Failed to generate an acceptable random number in 50 attempts in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getInt(1, 3) #1 {main} Next RuntimeException: Random number generation failed in php-src/test.php:17 Stack trace: #0 php-src/test.php(17): Random\Randomizer->getInt(1, 3) #1 {main} * Improve user_unsafe test Select parameters for ->getInt() that will actually lead to unsafe behavior. * Fix user_unsafe test If an engine fails once it will be permanently poisoned by setting `->last_unsafe`. This is undesirable for the test, because it skews the results. Fix this by creating a fresh engine for each "assertion". * Remove duplication in user_unsafe.phpt * Catch `Throwable` in user_unsafe.phpt As we print the full stringified exception we implicitly assert the type of the exception. No need to be overly specific in the catch block. * Throw an error if an engine returns an empty string * Throw an Error if range fails to find an acceptable number in 50 attempts
76 lines
2.2 KiB
C
76 lines
2.2 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| https://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Go Kudo <zeriyoshi@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_random.h"
|
|
|
|
static uint64_t generate(php_random_status *status)
|
|
{
|
|
php_random_status_state_user *s = status->state;
|
|
uint64_t result = 0;
|
|
size_t size;
|
|
zval retval;
|
|
|
|
zend_call_known_instance_method_with_0_params(s->generate_method, s->object, &retval);
|
|
|
|
if (EG(exception)) {
|
|
status->last_unsafe = true;
|
|
return 0;
|
|
}
|
|
|
|
/* Store generated size in a state */
|
|
size = Z_STRLEN(retval);
|
|
|
|
/* Guard for over 64-bit results */
|
|
if (size > sizeof(uint64_t)) {
|
|
size = sizeof(uint64_t);
|
|
}
|
|
status->last_generated_size = size;
|
|
|
|
if (size > 0) {
|
|
/* Endianness safe copy */
|
|
for (size_t i = 0; i < size; i++) {
|
|
result += ((uint64_t) (unsigned char) Z_STRVAL(retval)[i]) << (8 * i);
|
|
}
|
|
} else {
|
|
zend_throw_error(NULL, "A random engine must return a non-empty string");
|
|
status->last_unsafe = true;
|
|
return 0;
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
return result;
|
|
}
|
|
|
|
static zend_long range(php_random_status *status, zend_long min, zend_long max)
|
|
{
|
|
return php_random_range(&php_random_algo_user, status, min, max);
|
|
}
|
|
|
|
const php_random_algo php_random_algo_user = {
|
|
0,
|
|
sizeof(php_random_status_state_user),
|
|
NULL,
|
|
generate,
|
|
range,
|
|
NULL,
|
|
NULL,
|
|
};
|