Skip to content

Commit 5e6b90e

Browse files
authored
Fix GH-21730: Mt19937::__debugInfo() leaks state HashTable when the serialize callback fails (#21733)
Mt19937::__debugInfo() allocates a temporary HashTable with array_init(&t), calls the engine's serialize callback, and then inserts t into the return value. If the callback returns false, the method throws and hits RETURN_THROWS() before inserting t, so the HashTable leaks. PcgOneseq128XslRr64 and Xoshiro256StarStar alias the same method and share the leak. Niels Dossche fixed the same pattern in __serialize() via GH-20383 (720e006). That cleanup didn't touch __debugInfo(). Apply the same reordering here: insert t into return_value first, then let the callback populate it. RETURN_THROWS() then unwinds the return value cleanly. The path is latent in stock PHP because the three built-in serialize callbacks (mt19937, pcg, xoshiro) all return true, so no user code reaches the leak today. I'm fixing it for symmetry with GH-20383 and to keep the pattern from regressing if a future engine grows a failing serialize path. Closes GH-21730
1 parent 9f68d3c commit 5e6b90e

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

ext/random/engine_mt19937.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,11 @@ PHP_METHOD(Random_Engine_Mt19937, __debugInfo)
392392

393393
if (engine->engine.algo->serialize) {
394394
array_init(&t);
395+
zend_hash_str_add(Z_ARR_P(return_value), "__states", strlen("__states"), &t);
395396
if (!engine->engine.algo->serialize(engine->engine.state, Z_ARRVAL(t))) {
396397
zend_throw_exception(NULL, "Engine serialize failed", 0);
397398
RETURN_THROWS();
398399
}
399-
zend_hash_str_add(Z_ARR_P(return_value), "__states", strlen("__states"), &t);
400400
}
401401
}
402402
/* }}} */

0 commit comments

Comments
 (0)