[php-src] Issue #21730: ext/random: Mt19937::__debugInfo() leaks state HashTable when the serialize callback fails

[email protected] (iliaal)
Newsgroups php.bugs
Message-ID <[email protected]>
Issue: https://github.com/php/php-src/issues/21730
Author: iliaal

## Description

`Random\Engine\Mt19937::__debugInfo()` allocates a temporary `HashTable` with `array_init(&t)` and then calls `engine->engine.algo->serialize()`. If the callback returns `false`, the method throws "Engine serialize failed" and returns via `RETURN_THROWS()` before `t` gets inserted anywhere, so the HashTable leaks. `PcgOneseq128XslRr64::__debugInfo()` and `Xoshiro256StarStar::__debugInfo()` alias the same implementation and inherit the same leak.

Niels Dossche fixed this exact pattern in `__serialize()` in #20383 (720e0069829, "random: Fix memory leak when serialization fails"). That cleanup didn't touch `__debugInfo()`.

The path is latent in stock PHP because the three built-in `serialize` callbacks (mt19937, pcg, xoshiro) all return `true`, so no user code can reach the leak today. I'm filing it anyway for symmetry with the #20383 fix and to keep the pattern from regressing if a future engine's `serialize` grows a failure mode.

## Reproduction

Force the latent path with a one-line patch:

~~~diff
--- a/ext/random/engine_mt19937.c
+++ b/ext/random/engine_mt19937.c
@@ -174,6 +174,7 @@ static bool serialize(void *state, HashTable *data)
 {
 	php_random_status_state_mt19937 *s = state;
 	zval t;
+	return false;
~~~

Run:

~~~php
<?php
(new Random\Engine\Mt19937(1234))->__debugInfo();
~~~

under valgrind:

~~~
USE_ZEND_ALLOC=0 valgrind --leak-check=full --show-leak-kinds=definite \
    sapi/cli/php repro.php
~~~

Output:

~~~
==3067603== 56 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3067603==    at 0x4848899: malloc
==3067603==    by 0x70B5CC: __zend_malloc (zend_alloc.c:3544)
==3067603==    by 0x7B011C: _zend_new_array_0 (zend_hash.c:283)
==3067603==    by 0x59AAB4: zim_Random_Engine_Mt19937___debugInfo (engine_mt19937.c:396)
~~~

## PHP Version

master (PHP 8.6.0-dev). The block hasn't changed in 8.3/8.4/8.5 either, so all supported branches carry the same latent leak.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.