diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index a7bf219700650..9294b5361e9e7 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -86,6 +86,13 @@ PHP 8.4 INTERNALS UPGRADE NOTES the new php_random_result struct, replacing the last_generated_size member of the php_random_status struct and the generate_size member of the php_random_algo struct. + - The php_random_status struct has been removed, since the previous change + reduced it to a single void* member containing the actual state, resulting + in needless indirection. Functions taking a php_random_algo struct pointer + and a php_random_status struct pointer as separate parameters now take a + single php_random_algo_with_state struct by value, making it easier to + pass around the state with its associated algorithm and thus reducing + the chance for mistakes. - The CSPRNG API (php_random_(bytes|int)_*) is now provided by the new and much smaller php_random_csprng.h header. The new header is included in php_random.h for compatibility with existing users. diff --git a/ext/random/engine_combinedlcg.c b/ext/random/engine_combinedlcg.c index 4abb0bea48e6b..431132a175608 100644 --- a/ext/random/engine_combinedlcg.c +++ b/ext/random/engine_combinedlcg.c @@ -32,17 +32,17 @@ */ #define MODMULT(a, b, c, m, s) q = s / a; s = b * (s - a * q) - c * q; if (s < 0) s += m -static void seed(php_random_status *status, uint64_t seed) +static void seed(void *status, uint64_t seed) { - php_random_status_state_combinedlcg *s = status->state; + php_random_status_state_combinedlcg *s = status; s->state[0] = seed & 0xffffffffU; s->state[1] = seed >> 32; } -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { - php_random_status_state_combinedlcg *s = status->state; + php_random_status_state_combinedlcg *s = status; int32_t q, z; MODMULT(53668, 40014, 12211, 2147483563L, s->state[0]); @@ -59,14 +59,17 @@ static php_random_result generate(php_random_status *status) }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { - return php_random_range(&php_random_algo_combinedlcg, status, min, max); + return php_random_range((php_random_algo_with_state){ + .algo = &php_random_algo_combinedlcg, + .status = status, + }, min, max); } -static bool serialize(php_random_status *status, HashTable *data) +static bool serialize(void *status, HashTable *data) { - php_random_status_state_combinedlcg *s = status->state; + php_random_status_state_combinedlcg *s = status; zval t; for (uint32_t i = 0; i < 2; i++) { @@ -77,9 +80,9 @@ static bool serialize(php_random_status *status, HashTable *data) return true; } -static bool unserialize(php_random_status *status, HashTable *data) +static bool unserialize(void *status, HashTable *data) { - php_random_status_state_combinedlcg *s = status->state; + php_random_status_state_combinedlcg *s = status; zval *t; for (uint32_t i = 0; i < 2; i++) { diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index 6f2f4d5eef37b..4e7e6328b6545 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -139,14 +139,14 @@ static inline void mt19937_seed_state(php_random_status_state_mt19937 *state, ui mt19937_reload(state); } -static void seed(php_random_status *status, uint64_t seed) +static void seed(void *status, uint64_t seed) { - mt19937_seed_state(status->state, seed); + mt19937_seed_state(status, seed); } -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { - php_random_status_state_mt19937 *s = status->state; + php_random_status_state_mt19937 *s = status; uint32_t s1; if (s->count >= MT_N) { @@ -164,14 +164,17 @@ static php_random_result generate(php_random_status *status) }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { - return php_random_range(&php_random_algo_mt19937, status, min, max); + return php_random_range((php_random_algo_with_state){ + .algo = &php_random_algo_mt19937, + .status = status, + }, min, max); } -static bool serialize(php_random_status *status, HashTable *data) +static bool serialize(void *status, HashTable *data) { - php_random_status_state_mt19937 *s = status->state; + php_random_status_state_mt19937 *s = status; zval t; for (uint32_t i = 0; i < MT_N; i++) { @@ -186,9 +189,9 @@ static bool serialize(php_random_status *status, HashTable *data) return true; } -static bool unserialize(php_random_status *status, HashTable *data) +static bool unserialize(void *status, HashTable *data) { - php_random_status_state_mt19937 *s = status->state; + php_random_status_state_mt19937 *s = status; zval *t; /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */ @@ -251,8 +254,8 @@ PHPAPI void php_random_mt19937_seed_default(php_random_status_state_mt19937 *sta /* {{{ Random\Engine\Mt19937::__construct() */ PHP_METHOD(Random_Engine_Mt19937, __construct) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_mt19937 *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_mt19937 *state = engine.status; zend_long seed, mode = MT_RAND_MT19937; bool seed_is_null = true; @@ -290,12 +293,12 @@ PHP_METHOD(Random_Engine_Mt19937, __construct) /* {{{ Random\Engine\Mt19937::generate() */ PHP_METHOD(Random_Engine_Mt19937, generate) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; zend_string *bytes; ZEND_PARSE_PARAMETERS_NONE(); - php_random_result generated = engine->algo->generate(engine->status); + php_random_result generated = engine.algo->generate(engine.status); if (EG(exception)) { RETURN_THROWS(); } @@ -329,7 +332,7 @@ PHP_METHOD(Random_Engine_Mt19937, __serialize) /* state */ array_init(&t); - if (!engine->algo->serialize(engine->status, Z_ARRVAL(t))) { + if (!engine->engine.algo->serialize(engine->engine.status, Z_ARRVAL(t))) { zend_throw_exception(NULL, "Engine serialize failed", 0); RETURN_THROWS(); } @@ -372,7 +375,7 @@ PHP_METHOD(Random_Engine_Mt19937, __unserialize) zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name)); RETURN_THROWS(); } - if (!engine->algo->unserialize(engine->status, Z_ARRVAL_P(t))) { + if (!engine->engine.algo->unserialize(engine->engine.status, Z_ARRVAL_P(t))) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name)); RETURN_THROWS(); } @@ -392,9 +395,9 @@ PHP_METHOD(Random_Engine_Mt19937, __debugInfo) } ZVAL_ARR(return_value, zend_array_dup(engine->std.properties)); - if (engine->algo->serialize) { + if (engine->engine.algo->serialize) { array_init(&t); - if (!engine->algo->serialize(engine->status, Z_ARRVAL(t))) { + if (!engine->engine.algo->serialize(engine->engine.status, Z_ARRVAL(t))) { zend_throw_exception(NULL, "Engine serialize failed", 0); RETURN_THROWS(); } diff --git a/ext/random/engine_pcgoneseq128xslrr64.c b/ext/random/engine_pcgoneseq128xslrr64.c index 39f3c2f7253f4..2cafb5679298c 100644 --- a/ext/random/engine_pcgoneseq128xslrr64.c +++ b/ext/random/engine_pcgoneseq128xslrr64.c @@ -43,14 +43,14 @@ static inline void seed128(php_random_status_state_pcgoneseq128xslrr64 *s, php_r step(s); } -static void seed(php_random_status *status, uint64_t seed) +static void seed(void *status, uint64_t seed) { - seed128(status->state, php_random_uint128_constant(0ULL, seed)); + seed128(status, php_random_uint128_constant(0ULL, seed)); } -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { - php_random_status_state_pcgoneseq128xslrr64 *s = status->state; + php_random_status_state_pcgoneseq128xslrr64 *s = status; step(s); @@ -60,14 +60,17 @@ static php_random_result generate(php_random_status *status) }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { - return php_random_range(&php_random_algo_pcgoneseq128xslrr64, status, min, max); + return php_random_range((php_random_algo_with_state){ + .algo = &php_random_algo_pcgoneseq128xslrr64, + .status = status, + }, min, max); } -static bool serialize(php_random_status *status, HashTable *data) +static bool serialize(void *status, HashTable *data) { - php_random_status_state_pcgoneseq128xslrr64 *s = status->state; + php_random_status_state_pcgoneseq128xslrr64 *s = status; uint64_t u; zval z; @@ -82,9 +85,9 @@ static bool serialize(php_random_status *status, HashTable *data) return true; } -static bool unserialize(php_random_status *status, HashTable *data) +static bool unserialize(void *status, HashTable *data) { - php_random_status_state_pcgoneseq128xslrr64 *s = status->state; + php_random_status_state_pcgoneseq128xslrr64 *s = status; uint64_t u[2]; zval *t; @@ -142,8 +145,8 @@ PHPAPI void php_random_pcgoneseq128xslrr64_advance(php_random_status_state_pcgon /* {{{ Random\Engine\PcgOneseq128XslRr64::__construct */ PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, __construct) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_pcgoneseq128xslrr64 *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_pcgoneseq128xslrr64 *state = engine.status; zend_string *str_seed = NULL; zend_long int_seed = 0; bool seed_is_null = true; @@ -191,8 +194,8 @@ PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, __construct) /* {{{ Random\Engine\PcgOneseq128XslRr64::jump() */ PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, jump) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_pcgoneseq128xslrr64 *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_pcgoneseq128xslrr64 *state = engine.status; zend_long advance = 0; ZEND_PARSE_PARAMETERS_START(1, 1) diff --git a/ext/random/engine_secure.c b/ext/random/engine_secure.c index c7779463541fc..cd2d1d1ad705b 100644 --- a/ext/random/engine_secure.c +++ b/ext/random/engine_secure.c @@ -25,7 +25,7 @@ #include "Zend/zend_exceptions.h" -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { zend_ulong r = 0; @@ -37,7 +37,7 @@ static php_random_result generate(php_random_status *status) }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { zend_long result = 0; diff --git a/ext/random/engine_user.c b/ext/random/engine_user.c index 9d7521a29bf92..643476e79be1c 100644 --- a/ext/random/engine_user.c +++ b/ext/random/engine_user.c @@ -21,9 +21,9 @@ #include "php.h" #include "php_random.h" -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { - php_random_status_state_user *s = status->state; + php_random_status_state_user *s = status; uint64_t result = 0; size_t size; zval retval; @@ -65,9 +65,12 @@ static php_random_result generate(php_random_status *status) }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { - return php_random_range(&php_random_algo_user, status, min, max); + return php_random_range((php_random_algo_with_state){ + .algo = &php_random_algo_user, + .status = status, + }, min, max); } const php_random_algo php_random_algo_user = { diff --git a/ext/random/engine_xoshiro256starstar.c b/ext/random/engine_xoshiro256starstar.c index b32daf4a5a6dd..a606d9fd879a8 100644 --- a/ext/random/engine_xoshiro256starstar.c +++ b/ext/random/engine_xoshiro256starstar.c @@ -102,27 +102,30 @@ static inline void seed64(php_random_status_state_xoshiro256starstar *state, uin seed256(state, s[0], s[1], s[2], s[3]); } -static void seed(php_random_status *status, uint64_t seed) +static void seed(void *status, uint64_t seed) { - seed64(status->state, seed); + seed64(status, seed); } -static php_random_result generate(php_random_status *status) +static php_random_result generate(void *status) { return (php_random_result){ .size = sizeof(uint64_t), - .result = generate_state(status->state), + .result = generate_state(status), }; } -static zend_long range(php_random_status *status, zend_long min, zend_long max) +static zend_long range(void *status, zend_long min, zend_long max) { - return php_random_range(&php_random_algo_xoshiro256starstar, status, min, max); + return php_random_range((php_random_algo_with_state){ + .algo = &php_random_algo_xoshiro256starstar, + .status = status, + }, min, max); } -static bool serialize(php_random_status *status, HashTable *data) +static bool serialize(void *status, HashTable *data) { - php_random_status_state_xoshiro256starstar *s = status->state; + php_random_status_state_xoshiro256starstar *s = status; zval t; for (uint32_t i = 0; i < 4; i++) { @@ -133,9 +136,9 @@ static bool serialize(php_random_status *status, HashTable *data) return true; } -static bool unserialize(php_random_status *status, HashTable *data) +static bool unserialize(void *status, HashTable *data) { - php_random_status_state_xoshiro256starstar *s = status->state; + php_random_status_state_xoshiro256starstar *s = status; zval *t; /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */ @@ -180,8 +183,8 @@ PHPAPI void php_random_xoshiro256starstar_jump_long(php_random_status_state_xosh /* {{{ Random\Engine\Xoshiro256StarStar::jump() */ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jump) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_xoshiro256starstar *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_xoshiro256starstar *state = engine.status; ZEND_PARSE_PARAMETERS_NONE(); @@ -192,8 +195,8 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jump) /* {{{ Random\Engine\Xoshiro256StarStar::jumpLong() */ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jumpLong) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_xoshiro256starstar *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_xoshiro256starstar *state = engine.status; ZEND_PARSE_PARAMETERS_NONE(); @@ -204,8 +207,8 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jumpLong) /* {{{ Random\Engine\Xoshiro256StarStar::__construct */ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct) { - php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS); - php_random_status_state_xoshiro256starstar *state = engine->status->state; + php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine; + php_random_status_state_xoshiro256starstar *state = engine.status; zend_string *str_seed = NULL; zend_long int_seed = 0; bool seed_is_null = true; diff --git a/ext/random/gammasection.c b/ext/random/gammasection.c index 79bf63c866992..732f8a2b0d9b6 100644 --- a/ext/random/gammasection.c +++ b/ext/random/gammasection.c @@ -71,7 +71,7 @@ static uint64_t ceilint(double a, double b, double g) return (s != si) ? (uint64_t)si : (uint64_t)si + (e > 0); } -PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, php_random_status *status, double min, double max) +PHPAPI double php_random_gammasection_closed_open(php_random_algo_with_state engine, double min, double max) { double g = gamma_max(min, max); uint64_t hi = ceilint(min, max, g); @@ -80,7 +80,7 @@ PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, p return NAN; } - uint64_t k = 1 + php_random_range64(algo, status, hi - 1); /* [1, hi] */ + uint64_t k = 1 + php_random_range64(engine, hi - 1); /* [1, hi] */ if (fabs(min) <= fabs(max)) { if (k == hi) { @@ -99,7 +99,7 @@ PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, p } } -PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, php_random_status *status, double min, double max) +PHPAPI double php_random_gammasection_closed_closed(php_random_algo_with_state engine, double min, double max) { double g = gamma_max(min, max); uint64_t hi = ceilint(min, max, g); @@ -108,7 +108,7 @@ PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, return NAN; } - uint64_t k = php_random_range64(algo, status, hi); /* [0, hi] */ + uint64_t k = php_random_range64(engine, hi); /* [0, hi] */ if (fabs(min) <= fabs(max)) { if (k == hi) { @@ -131,7 +131,7 @@ PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, } } -PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, php_random_status *status, double min, double max) +PHPAPI double php_random_gammasection_open_closed(php_random_algo_with_state engine, double min, double max) { double g = gamma_max(min, max); uint64_t hi = ceilint(min, max, g); @@ -140,7 +140,7 @@ PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, p return NAN; } - uint64_t k = php_random_range64(algo, status, hi - 1); /* [0, hi - 1] */ + uint64_t k = php_random_range64(engine, hi - 1); /* [0, hi - 1] */ if (fabs(min) <= fabs(max)) { double k_hi, k_lo; @@ -159,7 +159,7 @@ PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, p } } -PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php_random_status *status, double min, double max) +PHPAPI double php_random_gammasection_open_open(php_random_algo_with_state engine, double min, double max) { double g = gamma_max(min, max); uint64_t hi = ceilint(min, max, g); @@ -168,7 +168,7 @@ PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php return NAN; } - uint64_t k = 1 + php_random_range64(algo, status, hi - 2); /* [1, hi - 1] */ + uint64_t k = 1 + php_random_range64(engine, hi - 2); /* [1, hi - 1] */ if (fabs(min) <= fabs(max)) { double k_hi, k_lo; diff --git a/ext/random/php_random.h b/ext/random/php_random.h index 88366cc4d69e7..2c896c3f9afff 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -66,10 +66,6 @@ PHPAPI zend_long php_mt_rand_common(zend_long min, zend_long max); PHPAPI void php_srand(zend_long seed); PHPAPI zend_long php_rand(void); -typedef struct _php_random_status_ { - void *state; -} php_random_status; - typedef struct _php_random_status_state_combinedlcg { int32_t state[2]; } php_random_status_state_combinedlcg; @@ -100,13 +96,18 @@ typedef struct _php_random_result { typedef struct _php_random_algo { const size_t state_size; - void (*seed)(php_random_status *status, uint64_t seed); - php_random_result (*generate)(php_random_status *status); - zend_long (*range)(php_random_status *status, zend_long min, zend_long max); - bool (*serialize)(php_random_status *status, HashTable *data); - bool (*unserialize)(php_random_status *status, HashTable *data); + void (*seed)(void *status, uint64_t seed); + php_random_result (*generate)(void *status); + zend_long (*range)(void *status, zend_long min, zend_long max); + bool (*serialize)(void *status, HashTable *data); + bool (*unserialize)(void *status, HashTable *data); } php_random_algo; +typedef struct _php_random_algo_with_state { + const php_random_algo *algo; + void *status; +} php_random_algo_with_state; + extern PHPAPI const php_random_algo php_random_algo_combinedlcg; extern PHPAPI const php_random_algo php_random_algo_mt19937; extern PHPAPI const php_random_algo php_random_algo_pcgoneseq128xslrr64; @@ -115,14 +116,12 @@ extern PHPAPI const php_random_algo php_random_algo_secure; extern PHPAPI const php_random_algo php_random_algo_user; typedef struct _php_random_engine { - const php_random_algo *algo; - php_random_status *status; + php_random_algo_with_state engine; zend_object std; } php_random_engine; typedef struct _php_random_randomizer { - const php_random_algo *algo; - php_random_status *status; + php_random_algo_with_state engine; bool is_userland_algo; zend_object std; } php_random_randomizer; @@ -155,17 +154,25 @@ static inline php_random_randomizer *php_random_randomizer_from_obj(zend_object # define Z_RANDOM_RANDOMIZER_P(zval) php_random_randomizer_from_obj(Z_OBJ_P(zval)); -PHPAPI php_random_status *php_random_status_alloc(const php_random_algo *algo, const bool persistent); -PHPAPI php_random_status *php_random_status_copy(const php_random_algo *algo, php_random_status *old_status, php_random_status *new_status); -PHPAPI void php_random_status_free(php_random_status *status, const bool persistent); +PHPAPI void *php_random_status_alloc(const php_random_algo *algo, const bool persistent); +PHPAPI void *php_random_status_copy(const php_random_algo *algo, void *old_status, void *new_status); +PHPAPI void php_random_status_free(void *status, const bool persistent); PHPAPI php_random_engine *php_random_engine_common_init(zend_class_entry *ce, zend_object_handlers *handlers, const php_random_algo *algo); PHPAPI void php_random_engine_common_free_object(zend_object *object); PHPAPI zend_object *php_random_engine_common_clone_object(zend_object *object); -PHPAPI uint32_t php_random_range32(const php_random_algo *algo, php_random_status *status, uint32_t umax); -PHPAPI uint64_t php_random_range64(const php_random_algo *algo, php_random_status *status, uint64_t umax); -PHPAPI zend_long php_random_range(const php_random_algo *algo, php_random_status *status, zend_long min, zend_long max); +PHPAPI uint32_t php_random_range32(php_random_algo_with_state engine, uint32_t umax); +PHPAPI uint64_t php_random_range64(php_random_algo_with_state engine, uint64_t umax); +PHPAPI zend_long php_random_range(php_random_algo_with_state engine, zend_long min, zend_long max); PHPAPI const php_random_algo *php_random_default_algo(void); -PHPAPI php_random_status *php_random_default_status(void); +PHPAPI void *php_random_default_status(void); + +static inline php_random_algo_with_state php_random_default_engine(void) +{ + return (php_random_algo_with_state){ + .algo = php_random_default_algo(), + .status = php_random_default_status(), + }; +} PHPAPI zend_string *php_random_bin2hex_le(const void *ptr, const size_t len); PHPAPI bool php_random_hex2bin_le(zend_string *hexstr, void *dest); @@ -179,10 +186,10 @@ PHPAPI void php_random_pcgoneseq128xslrr64_advance(php_random_status_state_pcgon PHPAPI void php_random_xoshiro256starstar_jump(php_random_status_state_xoshiro256starstar *state); PHPAPI void php_random_xoshiro256starstar_jump_long(php_random_status_state_xoshiro256starstar *state); -PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, php_random_status *status, double min, double max); -PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, php_random_status *status, double min, double max); -PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, php_random_status *status, double min, double max); -PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php_random_status *status, double min, double max); +PHPAPI double php_random_gammasection_closed_open(php_random_algo_with_state engine, double min, double max); +PHPAPI double php_random_gammasection_closed_closed(php_random_algo_with_state engine, double min, double max); +PHPAPI double php_random_gammasection_open_closed(php_random_algo_with_state engine, double min, double max); +PHPAPI double php_random_gammasection_open_open(php_random_algo_with_state engine, double min, double max); extern zend_module_entry random_module_entry; # define phpext_random_ptr &random_module_entry @@ -192,9 +199,9 @@ PHP_MSHUTDOWN_FUNCTION(random); PHP_RINIT_FUNCTION(random); ZEND_BEGIN_MODULE_GLOBALS(random) - php_random_status *combined_lcg; + php_random_status_state_combinedlcg *combined_lcg; bool combined_lcg_seeded; - php_random_status *mt19937; + php_random_status_state_mt19937 *mt19937; bool mt19937_seeded; int random_fd; ZEND_END_MODULE_GLOBALS(random) diff --git a/ext/random/random.c b/ext/random/random.c index efe14e0f6e38b..bd8e873118b2a 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -74,8 +74,11 @@ static zend_object_handlers random_engine_xoshiro256starstar_object_handlers; static zend_object_handlers random_engine_secure_object_handlers; static zend_object_handlers random_randomizer_object_handlers; -PHPAPI uint32_t php_random_range32(const php_random_algo *algo, php_random_status *status, uint32_t umax) +PHPAPI uint32_t php_random_range32(php_random_algo_with_state engine, uint32_t umax) { + const php_random_algo *algo = engine.algo; + void *status = engine.status; + uint32_t result, limit; size_t total_size = 0; uint32_t count = 0; @@ -130,8 +133,11 @@ PHPAPI uint32_t php_random_range32(const php_random_algo *algo, php_random_statu return result % umax; } -PHPAPI uint64_t php_random_range64(const php_random_algo *algo, php_random_status *status, uint64_t umax) +PHPAPI uint64_t php_random_range64(php_random_algo_with_state engine, uint64_t umax) { + const php_random_algo *algo = engine.algo; + void *status = engine.status; + uint64_t result, limit; size_t total_size = 0; uint32_t count = 0; @@ -220,34 +226,24 @@ static void randomizer_free_obj(zend_object *object) { php_random_randomizer *randomizer = php_random_randomizer_from_obj(object); if (randomizer->is_userland_algo) { - php_random_status_free(randomizer->status, false); + php_random_status_free(randomizer->engine.status, false); } zend_object_std_dtor(&randomizer->std); } -PHPAPI php_random_status *php_random_status_alloc(const php_random_algo *algo, const bool persistent) +PHPAPI void *php_random_status_alloc(const php_random_algo *algo, const bool persistent) { - php_random_status *status = pecalloc(1, sizeof(php_random_status), persistent); - - status->state = algo->state_size > 0 ? pecalloc(1, algo->state_size, persistent) : NULL; - - return status; + return algo->state_size > 0 ? pecalloc(1, algo->state_size, persistent) : NULL; } -PHPAPI php_random_status *php_random_status_copy(const php_random_algo *algo, php_random_status *old_status, php_random_status *new_status) +PHPAPI void *php_random_status_copy(const php_random_algo *algo, void *old_status, void *new_status) { - new_status->state = memcpy(new_status->state, old_status->state, algo->state_size); - - return new_status; + return memcpy(new_status, old_status, algo->state_size); } -PHPAPI void php_random_status_free(php_random_status *status, const bool persistent) +PHPAPI void php_random_status_free(void *status, const bool persistent) { - if (status != NULL) { - pefree(status->state, persistent); - } - pefree(status, persistent); } @@ -258,8 +254,10 @@ PHPAPI php_random_engine *php_random_engine_common_init(zend_class_entry *ce, ze zend_object_std_init(&engine->std, ce); object_properties_init(&engine->std, ce); - engine->algo = algo; - engine->status = php_random_status_alloc(engine->algo, false); + engine->engine = (php_random_algo_with_state){ + .algo = algo, + .status = php_random_status_alloc(algo, false) + }; engine->std.handlers = handlers; return engine; @@ -269,7 +267,7 @@ PHPAPI void php_random_engine_common_free_object(zend_object *object) { php_random_engine *engine = php_random_engine_from_obj(object); - php_random_status_free(engine->status, false); + php_random_status_free(engine->engine.status, false); zend_object_std_dtor(object); } @@ -278,9 +276,9 @@ PHPAPI zend_object *php_random_engine_common_clone_object(zend_object *object) php_random_engine *old_engine = php_random_engine_from_obj(object); php_random_engine *new_engine = php_random_engine_from_obj(old_engine->std.ce->create_object(old_engine->std.ce)); - new_engine->algo = old_engine->algo; - if (old_engine->status) { - new_engine->status = php_random_status_copy(old_engine->algo, old_engine->status, new_engine->status); + new_engine->engine.algo = old_engine->engine.algo; + if (old_engine->engine.status) { + new_engine->engine.status = php_random_status_copy(old_engine->engine.algo, old_engine->engine.status, new_engine->engine.status); } zend_objects_clone_members(&new_engine->std, &old_engine->std); @@ -289,15 +287,15 @@ PHPAPI zend_object *php_random_engine_common_clone_object(zend_object *object) } /* {{{ php_random_range */ -PHPAPI zend_long php_random_range(const php_random_algo *algo, php_random_status *status, zend_long min, zend_long max) +PHPAPI zend_long php_random_range(php_random_algo_with_state engine, zend_long min, zend_long max) { zend_ulong umax = (zend_ulong) max - (zend_ulong) min; if (umax > UINT32_MAX) { - return (zend_long) (php_random_range64(algo, status, umax) + min); + return (zend_long) (php_random_range64(engine, umax) + min); } - return (zend_long) (php_random_range32(algo, status, umax) + min); + return (zend_long) (php_random_range32(engine, umax) + min); } /* }}} */ @@ -309,12 +307,12 @@ PHPAPI const php_random_algo *php_random_default_algo(void) /* }}} */ /* {{{ php_random_default_status */ -PHPAPI php_random_status *php_random_default_status(void) +PHPAPI void *php_random_default_status(void) { - php_random_status *status = RANDOM_G(mt19937); + php_random_status_state_mt19937 *status = RANDOM_G(mt19937); if (!RANDOM_G(mt19937_seeded)) { - php_random_mt19937_seed_default(status->state); + php_random_mt19937_seed_default(status); RANDOM_G(mt19937_seeded) = true; } @@ -392,10 +390,10 @@ PHPAPI bool php_random_hex2bin_le(zend_string *hexstr, void *dest) /* {{{ php_combined_lcg */ PHPAPI double php_combined_lcg(void) { - php_random_status *status = RANDOM_G(combined_lcg); + php_random_status_state_combinedlcg *status = RANDOM_G(combined_lcg); if (!RANDOM_G(combined_lcg_seeded)) { - php_random_combinedlcg_seed_default(status->state); + php_random_combinedlcg_seed_default(status); RANDOM_G(combined_lcg_seeded) = true; } @@ -429,8 +427,7 @@ 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) { - php_random_status *status = php_random_default_status(); - php_random_status_state_mt19937 *s = status->state; + php_random_status_state_mt19937 *s = php_random_default_status(); if (s->mode == MT_RAND_MT19937) { return php_mt_rand_range(min, max); @@ -476,8 +473,7 @@ PHP_FUNCTION(mt_srand) zend_long seed = 0; bool seed_is_null = true; zend_long mode = MT_RAND_MT19937; - php_random_status *status = RANDOM_G(mt19937); - php_random_status_state_mt19937 *state = status->state; + php_random_status_state_mt19937 *state = RANDOM_G(mt19937); ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL @@ -493,9 +489,9 @@ PHP_FUNCTION(mt_srand) } if (seed_is_null) { - php_random_mt19937_seed_default(status->state); + php_random_mt19937_seed_default(state); } else { - php_random_algo_mt19937.seed(status, (uint64_t) seed); + php_random_algo_mt19937.seed(state, (uint64_t) seed); } RANDOM_G(mt19937_seeded) = true; } diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 54571365d4e75..1f26aecacd073 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -33,12 +33,15 @@ static inline void randomizer_common_init(php_random_randomizer *randomizer, zen php_random_engine *engine = php_random_engine_from_obj(engine_object); /* Copy engine pointers */ - randomizer->algo = engine->algo; - randomizer->status = engine->status; + randomizer->engine = engine->engine; } else { /* Self allocation */ - randomizer->status = php_random_status_alloc(&php_random_algo_user, false); - php_random_status_state_user *state = randomizer->status->state; + php_random_status_state_user *state = php_random_status_alloc(&php_random_algo_user, false); + randomizer->engine = (php_random_algo_with_state){ + .algo = &php_random_algo_user, + .status = state, + }; + zend_string *mname; zend_function *generate_method; @@ -50,9 +53,6 @@ static inline void randomizer_common_init(php_random_randomizer *randomizer, zen state->object = engine_object; state->generate_method = generate_method; - /* Copy common pointers */ - randomizer->algo = &php_random_algo_user; - /* Mark self-allocated for memory management */ randomizer->is_userland_algo = true; } @@ -93,6 +93,8 @@ PHP_METHOD(Random_Randomizer, __construct) PHP_METHOD(Random_Randomizer, nextFloat) { php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + php_random_algo_with_state engine = randomizer->engine; + uint64_t result; size_t total_size; @@ -101,7 +103,7 @@ PHP_METHOD(Random_Randomizer, nextFloat) result = 0; total_size = 0; do { - php_random_result r = randomizer->algo->generate(randomizer->status); + php_random_result r = engine.algo->generate(engine.status); result = result | (r.result << (total_size * 8)); total_size += r.size; if (EG(exception)) { @@ -169,28 +171,28 @@ PHP_METHOD(Random_Randomizer, getFloat) RETURN_THROWS(); } - RETURN_DOUBLE(php_random_gammasection_closed_open(randomizer->algo, randomizer->status, min, max)); + RETURN_DOUBLE(php_random_gammasection_closed_open(randomizer->engine, min, max)); case 'C' + sizeof("ClosedClosed") - 1: if (UNEXPECTED(max < min)) { zend_argument_value_error(2, "must be greater than or equal to argument #1 ($min)"); RETURN_THROWS(); } - RETURN_DOUBLE(php_random_gammasection_closed_closed(randomizer->algo, randomizer->status, min, max)); + RETURN_DOUBLE(php_random_gammasection_closed_closed(randomizer->engine, min, max)); case 'O' + sizeof("OpenClosed") - 1: if (UNEXPECTED(max <= min)) { zend_argument_value_error(2, "must be greater than argument #1 ($min)"); RETURN_THROWS(); } - RETURN_DOUBLE(php_random_gammasection_open_closed(randomizer->algo, randomizer->status, min, max)); + RETURN_DOUBLE(php_random_gammasection_open_closed(randomizer->engine, min, max)); case 'O' + sizeof("OpenOpen") - 1: if (UNEXPECTED(max <= min)) { zend_argument_value_error(2, "must be greater than argument #1 ($min)"); RETURN_THROWS(); } - RETVAL_DOUBLE(php_random_gammasection_open_open(randomizer->algo, randomizer->status, min, max)); + RETVAL_DOUBLE(php_random_gammasection_open_open(randomizer->engine, min, max)); if (UNEXPECTED(isnan(Z_DVAL_P(return_value)))) { zend_value_error("The given interval is empty, there are no floats between argument #1 ($min) and argument #2 ($max)."); @@ -208,10 +210,11 @@ PHP_METHOD(Random_Randomizer, getFloat) PHP_METHOD(Random_Randomizer, nextInt) { php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + php_random_algo_with_state engine = randomizer->engine; ZEND_PARSE_PARAMETERS_NONE(); - php_random_result result = randomizer->algo->generate(randomizer->status); + php_random_result result = engine.algo->generate(engine.status); if (EG(exception)) { RETURN_THROWS(); } @@ -228,6 +231,8 @@ PHP_METHOD(Random_Randomizer, nextInt) PHP_METHOD(Random_Randomizer, getInt) { php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + php_random_algo_with_state engine = randomizer->engine; + uint64_t result; zend_long min, max; @@ -242,10 +247,10 @@ PHP_METHOD(Random_Randomizer, getInt) } if (UNEXPECTED( - randomizer->algo->range == php_random_algo_mt19937.range - && ((php_random_status_state_mt19937 *) randomizer->status->state)->mode != MT_RAND_MT19937 + engine.algo->range == php_random_algo_mt19937.range + && ((php_random_status_state_mt19937 *) engine.status)->mode != MT_RAND_MT19937 )) { - uint64_t r = php_random_algo_mt19937.generate(randomizer->status).result >> 1; + uint64_t r = php_random_algo_mt19937.generate(engine.status).result >> 1; /* This is an inlined version of the RAND_RANGE_BADSCALING macro that does not invoke UB when encountering * (max - min) > ZEND_LONG_MAX. @@ -254,7 +259,7 @@ PHP_METHOD(Random_Randomizer, getInt) result = (zend_long) (offset + min); } else { - result = randomizer->algo->range(randomizer->status, min, max); + result = engine.algo->range(engine.status, min, max); } if (EG(exception)) { @@ -269,6 +274,8 @@ PHP_METHOD(Random_Randomizer, getInt) PHP_METHOD(Random_Randomizer, getBytes) { php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + php_random_algo_with_state engine = randomizer->engine; + zend_string *retval; zend_long length; size_t total_size = 0; @@ -285,7 +292,7 @@ PHP_METHOD(Random_Randomizer, getBytes) retval = zend_string_alloc(length, 0); while (total_size < length) { - php_random_result result = randomizer->algo->generate(randomizer->status); + php_random_result result = engine.algo->generate(engine.status); if (EG(exception)) { zend_string_free(retval); RETURN_THROWS(); @@ -314,7 +321,7 @@ PHP_METHOD(Random_Randomizer, shuffleArray) ZEND_PARSE_PARAMETERS_END(); ZVAL_DUP(return_value, array); - if (!php_array_data_shuffle(randomizer->algo, randomizer->status, return_value)) { + if (!php_array_data_shuffle(randomizer->engine, return_value)) { RETURN_THROWS(); } } @@ -335,7 +342,7 @@ PHP_METHOD(Random_Randomizer, shuffleBytes) } RETVAL_STRINGL(ZSTR_VAL(bytes), ZSTR_LEN(bytes)); - if (!php_binary_string_shuffle(randomizer->algo, randomizer->status, Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value))) { + if (!php_binary_string_shuffle(randomizer->engine, Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value))) { RETURN_THROWS(); } } @@ -354,8 +361,7 @@ PHP_METHOD(Random_Randomizer, pickArrayKeys) ZEND_PARSE_PARAMETERS_END(); if (!php_array_pick_keys( - randomizer->algo, - randomizer->status, + randomizer->engine, input, num_req, return_value, @@ -377,6 +383,8 @@ PHP_METHOD(Random_Randomizer, pickArrayKeys) PHP_METHOD(Random_Randomizer, getBytesFromString) { php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + php_random_algo_with_state engine = randomizer->engine; + zend_long length; zend_string *source, *retval; size_t total_size = 0; @@ -403,7 +411,7 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) if (max_offset > 0xff) { while (total_size < length) { - uint64_t offset = randomizer->algo->range(randomizer->status, 0, max_offset); + uint64_t offset = engine.algo->range(engine.status, 0, max_offset); if (EG(exception)) { zend_string_free(retval); @@ -424,7 +432,7 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) int failures = 0; while (total_size < length) { - php_random_result result = randomizer->algo->generate(randomizer->status); + php_random_result result = engine.algo->generate(engine.status); if (EG(exception)) { zend_string_free(retval); RETURN_THROWS(); diff --git a/ext/standard/array.c b/ext/standard/array.c index 850e8fa4502fe..0784897421803 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3211,8 +3211,11 @@ PHP_FUNCTION(range) #undef RANGE_CHECK_LONG_INIT_ARRAY /* {{{ php_array_data_shuffle */ -PHPAPI bool php_array_data_shuffle(const php_random_algo *algo, php_random_status *status, zval *array) /* {{{ */ +PHPAPI bool php_array_data_shuffle(php_random_algo_with_state engine, zval *array) /* {{{ */ { + const php_random_algo *algo = engine.algo; + void *status = engine.status; + int64_t idx, j, n_elems, rnd_idx, n_left; zval *zv, temp; HashTable *hash; @@ -3310,7 +3313,7 @@ PHP_FUNCTION(shuffle) Z_PARAM_ARRAY_EX(array, 0, 1) ZEND_PARSE_PARAMETERS_END(); - php_array_data_shuffle(php_random_default_algo(), php_random_default_status(), array); + php_array_data_shuffle(php_random_default_engine(), array); RETURN_TRUE; } @@ -6191,8 +6194,11 @@ PHP_FUNCTION(array_multisort) /* }}} */ /* {{{ php_array_pick_keys */ -PHPAPI bool php_array_pick_keys(const php_random_algo *algo, php_random_status *status, zval *input, zend_long num_req, zval *retval, bool silent) +PHPAPI bool php_array_pick_keys(php_random_algo_with_state engine, zval *input, zend_long num_req, zval *retval, bool silent) { + const php_random_algo *algo = engine.algo; + void *status = engine.status; + HashTable *ht = Z_ARRVAL_P(input); uint32_t num_avail = zend_hash_num_elements(ht); zend_long i, randval; @@ -6350,8 +6356,7 @@ PHP_FUNCTION(array_rand) ZEND_PARSE_PARAMETERS_END(); if (!php_array_pick_keys( - php_random_default_algo(), - php_random_default_status(), + php_random_default_engine(), input, num_req, return_value, diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index 5d42a22f42040..2a35af6038083 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -31,8 +31,8 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src); PHPAPI int php_multisort_compare(const void *a, const void *b); PHPAPI zend_long php_count_recursive(HashTable *ht); -PHPAPI bool php_array_data_shuffle(const php_random_algo *algo, php_random_status *status, zval *array); -PHPAPI bool php_array_pick_keys(const php_random_algo *algo, php_random_status *status, zval *input, zend_long num_req, zval *retval, bool silent); +PHPAPI bool php_array_data_shuffle(php_random_algo_with_state engine, zval *array); +PHPAPI bool php_array_pick_keys(php_random_algo_with_state engine, zval *input, zend_long num_req, zval *retval, bool silent); #define PHP_EXTR_OVERWRITE 0 #define PHP_EXTR_SKIP 1 diff --git a/ext/standard/php_string.h b/ext/standard/php_string.h index e3143a51da6bf..654ce5d0eddff 100644 --- a/ext/standard/php_string.h +++ b/ext/standard/php_string.h @@ -62,7 +62,7 @@ PHPAPI int string_natural_compare_function_ex(zval *result, zval *op1, zval *op2 PHPAPI int string_natural_compare_function(zval *result, zval *op1, zval *op2); PHPAPI int string_natural_case_compare_function(zval *result, zval *op1, zval *op2); -PHPAPI bool php_binary_string_shuffle(const php_random_algo *algo, php_random_status *status, char *str, zend_long len); +PHPAPI bool php_binary_string_shuffle(php_random_algo_with_state engine, char *str, zend_long len); #ifdef _REENTRANT # ifdef PHP_WIN32 diff --git a/ext/standard/string.c b/ext/standard/string.c index e1c9f83540664..8d139a7289661 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -5953,8 +5953,11 @@ PHP_FUNCTION(str_rot13) /* }}} */ /* {{{ php_binary_string_shuffle */ -PHPAPI bool php_binary_string_shuffle(const php_random_algo *algo, php_random_status *status, char *str, zend_long len) /* {{{ */ +PHPAPI bool php_binary_string_shuffle(php_random_algo_with_state engine, char *str, zend_long len) /* {{{ */ { + const php_random_algo *algo = engine.algo; + void *status = engine.status; + int64_t n_elems, rnd_idx, n_left; char temp; @@ -5996,8 +5999,7 @@ PHP_FUNCTION(str_shuffle) RETVAL_STRINGL(ZSTR_VAL(arg), ZSTR_LEN(arg)); if (Z_STRLEN_P(return_value) > 1) { php_binary_string_shuffle( - php_random_default_algo(), - php_random_default_status(), + php_random_default_engine(), Z_STRVAL_P(return_value), Z_STRLEN_P(return_value) );