1
0
mirror of https://github.com/php/php-src.git synced 2026-03-29 03:32:20 +02:00
Commit Graph

26 Commits

Author SHA1 Message Date
Tim Düsterhus
e059498c04 random: Fix unknown mt_srand() compatibility for unknown modes (#13544)
PHP 8.1 and below interpreted unknown modes as `MT_RAND_MT19937`, but PHP 8.2+
interprets them as `MT_RAND_PHP`.

Align the behavior with PHP 8.1 and below, because folks should be steered
towards the standard mode.
2024-02-29 18:05:59 +01:00
Tim Düsterhus
97c6da1dec random/standard: Correctly handle broken engines in php_array_pick_keys (#13138) 2024-01-14 13:01:29 +01:00
Máté Kocsis
7517cf3b97 Merge branch 'PHP-8.1' into PHP-8.2
- PHP-8.1:
  Fix GH-10292 1st param of mt_srand() has UNKNOWN default on PHP <8.3
2023-01-24 19:53:09 +01:00
Tim Düsterhus
7f0b228f48 Fix pre-PHP 8.2 compatibility for php_mt_rand_range() with MT_RAND_PHP (#9839)
* Fix pre-PHP 8.2 compatibility for php_mt_rand_range() with MT_RAND_PHP

As some left-over comments indicated:

> Legacy mode deliberately not inside php_mt_rand_range()
> to prevent other functions being affected

The broken scaler was only used for `php_mt_rand_common()`, not
`php_mt_rand_range()`. The former is only used for `mt_rand()`, whereas the
latter is used for `array_rand()` and others.

With the refactoring for the introduction of ext/random `php_mt_rand_common()`
and `php_mt_rand_range()` were accidentally unified, thus introducing a
behavioral change that was reported in FakerPHP/Faker#528.

This commit moves the checks for `MT_RAND_PHP` from the general-purpose
`range()` function back into `php_mt_rand_common()` and also into
`Randomizer::getInt()` for drop-in compatibility with `mt_rand()`.

* [ci skip] NEWS for `MT_RAND_PHP` compatibility
2022-10-28 16:52:43 +02:00
Tim Düsterhus
ddf7a5d4d9 random: Validate that the arrays do not contain extra elements when unserializing (#9458)
* Apply `var_dump()` in 02_engine/all_serialize_error.phpt

This ensures that an undetected serialization error is clear identifiable in the output.

* random: Validate that the arrays do not contain extra elements when unserializing
2022-09-05 17:33:36 +02:00
Tim Düsterhus
f7d426cca6 Unify structure for ext/random's randomizer tests (#9410)
* Unify structure for ext/random's engine tests (2)

This makes adjustments that were missed in
2d6a883b3a.

* Add `engines.inc` for ext/random tests

* Unify structure for ext/random's randomizer tests
2022-08-31 19:22:39 +02:00
Máté Kocsis
adb45a63c0 Fix GH-9186 @strict-properties can be bypassed using unserialization (#9354)
* Emit deprecation warnings when adding dynamic properties to classes during unserialization - this will become an Error in php 9.0.
  (Adding dynamic properties in other contexts was already a deprecation warning - the use case of unserialization was overlooked)
* Throw an error when attempting to add a dynamic property to a `readonly` class when unserializing
* Add new serialization methods `__serialize`/`__unserialize` for SplFixedArray to avoid creating deprecated dynamic
  properties that would then be added to the backing fixed-size array
* Don't add named dynamic/declared properties (e.g. $obj->foo) of SplFixedArray to the backing array when unserializing
* Update tests to declare properties or to expect the deprecation warning
* Add news entry

Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
2022-08-30 07:46:32 -04:00
Tim Düsterhus
0f696e2934 Fix rand_range32() for umax = UINT32_MAX (#9416)
* Fix rand_range32() for umax = UINT32_MAX

This was introduced in the commit that added the random extension:
4d8dd8d258.

Resolves GH-9415

* [ci skip] Rename `$r` to `$randomizer` in gh9415.phpt

* Make gh9415.phpt deterministic

* Make gh9415.phpt compatible with 32-bit
2022-08-24 14:25:51 +02:00
Tim Düsterhus
2d6a883b3a Unify structure for ext/random's engine tests (#9321)
* Remove user_xoshiro128plusplus.phpt

This test does not exercise any of the code paths of the random extension and
thus is no value-add.

* Unify structure for ext/random's engine tests
2022-08-23 23:55:11 +02:00
Tim Düsterhus
3b48a2044d Replace RuntimeException in Randomizer::nextInt() by RandomException (#9305)
* Replace RuntimeException in Randomizer::nextInt() by RandomException

* Add ext/random/tests/03_randomizer/nextint_error.phpt
2022-08-15 11:06:03 +02:00
Tim Düsterhus
1cd2d731ef Handle all-zero state in Xoshiro256** (#9250)
- Retry if the CSPRNG generates a zero state.
- Throw ValueError if the user passes a zero state.

Fixes GH-9249
2022-08-05 14:38:57 +02:00
Tim Düsterhus
a191710a21 [ci skip] Run dos2unix on ext/random tests
One test inconsistently had CRLF newlines.
2022-08-04 21:01:04 +02:00
Tim Düsterhus
3331832b04 Add ext/random Exception hierarchy (#9220)
* Add Random\Random{Error,Exception} and Random\BrokenRandomEngineError

* Throw BrokenRandomEngineError

* Throw RandomException on seeding failure

* Throw RandomException when CSPRNG fails

* Remove unused include from ext/random/engine_combinedlcg.c

* Remove unused include from ext/random/engine_secure.c

* Remove unused include from ext/random/random.c

* [ci skip] Add ext/random Exception hierarchy to NEWS

* [ci skip] Add the change of Exception for random_(int|bytes) to UPGRADING
2022-08-02 20:04:28 +02:00
Tim Düsterhus
a6922fdecd Clean up the implementation of Randomizer::__construct() (#9222)
* Verify that the engine doesn't change in construct_twice.phpt

* Clean up the implementation of Randomizer::__construct()

Instead of manually checking whether the constructor was already called, we
rely on the `readonly` modifier of the `$engine` property.

Additionally use `object_init_ex()` instead of manually calling
`->create_object()`.
2022-08-02 17:30:18 +02:00
Tim Düsterhus
54e406cc50 Clean up nested exceptions without value-add in ext/random (#9211)
* Remove exception in Randomizer::shuffleBytes()

The only way that `php_binary_string_shuffle` fails is when the engine itself
fails. With the currently available list of engines we have:

- Mt19937            : Infallible.
- PcgOneseq128XslRr64: Infallible.
- Xoshiro256StarStar : Infallible.
- Secure             : Practically infallible on modern systems.
                       Exception messages were cleaned up in GH-9169.
- User               : Error when returning an empty string.
                       Error when seriously biased (range() fails).
                       And whatever Throwable the userland developer decides to use.

So the existing engines are either infallible or throw an Exception/Error with
a high quality message themselves, making this exception not a value-add and
possibly confusing.

* Remove exception in Randomizer::shuffleArray()

Same reasoning as in the previous commit applies.

* Remove exception in Randomizer::getInt()

Same reasoning as in the previous commit applies.

* Remove exception in Randomizer::nextInt()

Same reasoning as in the previous commit applies, except that it won't throw on
a seriously biased user engine, as `range()` is not used.

* Remove exception in Randomizer::getBytes()

Same reasoning as in the previous commit applies.

* Remove exception in Mt19937::generate()

This implementation is shared across all native engines. Thus the same
reasoning as the previous commits applies, except that the User engine does not
use this method. Thus is only applicable to the Secure engine, which is the
only fallible native engine.

* [ci skip] Add cleanup of Randomizer exceptions to NEWS
2022-08-02 17:29:36 +02:00
Tim Düsterhus
c63f18dd9b Unify ext/random unserialize errors with ext/date (#9185)
* Unify ext/random unserialize errors with ext/date

- Use `Error` instead of `Exception`.
- Adjust wording.

* Make `zend_read_property` silent in `Randomizer::__unserialize()`

Having:

> Error: Typed property Random\Randomizer::$engine must not be accessed before
> initialization

is not a value-add in this case.

* Insert the actual class name in the unserialization error of Engines

* Revert unserialization failure back to Exception from Error

see https://news-web.php.net/php.internals/118311
2022-08-02 09:00:37 +02:00
Anton Smirnov
50bd8ba51c PcgOneseq128XslRr64::jump(): Throw ValueError for negative $advance (#9213)
* PCG64: $advance must be non-negative

Closes GH-9212
2022-08-01 13:47:14 +01:00
zeriyoshi
4e92c74654 random: split Randomizer::getInt() without argument to Randomizer::nextInt()
Since argument overloading is not safe for reflection, the method needed
to be split appropriately.

Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>

Closes GH-9057.
2022-08-01 12:19:22 +02:00
Tim Düsterhus
53ca24d46e Improve phrasing in argument value errors in ext/random (#9206)
This rephrases the error message for argument errors to be a proper English
sentence.

Co-authored-by: Máté Kocsis <kocsismate@woohoolabs.com>
2022-07-31 19:27:28 +02:00
Tim Düsterhus
d058acb4ac Use ValueError if an invalid mode is passed to Mt19937 (#9159) 2022-07-27 09:03:02 +02:00
Tim Düsterhus
60f149f7ad Improve error reporting in random extension (#9071)
* 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
2022-07-25 09:00:49 +02:00
Go Kudo
34b352d121 Fix memory leak on Randomizer::__construct() call twice (#9091)
When Radomizer::__construct() was called with no arguments, Randomizer\Engine\Secure was implicitly instantiate and memory was leaking.
Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>
2022-07-24 03:09:14 +09:00
Tim Düsterhus
ab5491f505 Fix shift in rand_rangeXX() (#9088)
The previous shifting logic is problematic for two reasons:

1. It invokes undefined behavior when the `->last_generated_size` is at least
as large as the target integer in `result`, because the shift is larger than
the target integer. This was reported in GH-9083.

2. It expands the returned bytes in a big-endian fashion: Earlier bytes are
shifting into the most-significant position. As all the other logic in the
random extension treats byte-strings as little-endian numbers this is
inconsistent.

By fixing the second issue, we can implicitly fix the first one: Instead of
shifting the existing bits by the number of "newly added" bits, we shift the
newly added bits by the number of existing bits. As we stop requesting new bits
once the total_size reached the size of the target integer we can be sure to
never invoke undefined behavior during shifting.

The get_int_user.phpt test was adjusted to verify the little-endian behavior.
It generates a single byte per call and we expect the first byte generated to
appear at the start of the resulting number.

see GH-9056 for a previous fix in the same area.
Fixes GH-9083 which reports the undefined behavior.
Resolves GH-9085 which was an alternative attempt to fix GH-9083.
2022-07-22 10:45:17 +01:00
Tim Düsterhus
804c3fc821 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()
2022-07-20 17:33:10 +02:00
Tim Düsterhus
998ede7123 Fix segmentation fault in Randomizer::getBytes() if a user engine throws (#9055)
This fixes:

    ==374077== Use of uninitialised value of size 8
    ==374077==    at 0x532B06: generate (engine_user.c:39)
    ==374077==    by 0x533F71: zim_Random_Randomizer_getBytes (randomizer.c:152)
    ==374077==    by 0x7F581D: ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1885)
    ==374077==    by 0x8725BE: execute_ex (zend_vm_execute.h:55930)
    ==374077==    by 0x877DB4: zend_execute (zend_vm_execute.h:60253)
    ==374077==    by 0x7B0FD4: zend_execute_scripts (zend.c:1770)
    ==374077==    by 0x6F1647: php_execute_script (main.c:2535)
    ==374077==    by 0x937DA4: do_cli (php_cli.c:964)
    ==374077==    by 0x938C3A: main (php_cli.c:1333)
    ==374077==
    ==374077== Invalid read of size 8
    ==374077==    at 0x532B06: generate (engine_user.c:39)
    ==374077==    by 0x533F71: zim_Random_Randomizer_getBytes (randomizer.c:152)
    ==374077==    by 0x7F581D: ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1885)
    ==374077==    by 0x8725BE: execute_ex (zend_vm_execute.h:55930)
    ==374077==    by 0x877DB4: zend_execute (zend_vm_execute.h:60253)
    ==374077==    by 0x7B0FD4: zend_execute_scripts (zend.c:1770)
    ==374077==    by 0x6F1647: php_execute_script (main.c:2535)
    ==374077==    by 0x937DA4: do_cli (php_cli.c:964)
    ==374077==    by 0x938C3A: main (php_cli.c:1333)
    ==374077==  Address 0x11 is not stack'd, malloc'd or (recently) free'd
2022-07-20 17:32:22 +02:00
Go Kudo
4d8dd8d258 Implement Random Extension
https://wiki.php.net/rfc/rng_extension
https://wiki.php.net/rfc/random_extension_improvement
2022-07-19 10:27:38 +01:00