mirror of
https://github.com/php/php-src.git
synced 2026-04-06 07:32:54 +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
77 lines
2.2 KiB
C
77 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,
|
|
};
|