Skip to content

Commit 8aa8116

Browse files
committed
ext/pcntl: Children should not inherit random seeds
Fix GH-21351
1 parent 77925b9 commit 8aa8116

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
pcntl_fork() reseeds MT rand in child processes (GH-21351)
3+
--EXTENSIONS--
4+
pcntl
5+
posix
6+
--FILE--
7+
<?php
8+
/*
9+
* When MT rand is seeded before fork(), child processes must not inherit
10+
* the parent's MT state verbatim — each child should get a fresh seed
11+
* so that mt_rand() / array_rand() / shuffle() produce different sequences.
12+
*/
13+
14+
// Ensure MT rand is seeded before forking
15+
mt_srand(42);
16+
mt_rand();
17+
18+
$tmpfile = tempnam(sys_get_temp_dir(), 'pcntl_mt_');
19+
20+
$children = 5;
21+
for ($i = 0; $i < $children; $i++) {
22+
$pid = pcntl_fork();
23+
if ($pid == -1) {
24+
die("fork failed");
25+
} else if ($pid == 0) {
26+
// Child: generate a value and write it to the shared temp file.
27+
// If reseeding works, children should not all produce the same value.
28+
$val = mt_rand(0, PHP_INT_MAX);
29+
file_put_contents($tmpfile, $val . "\n", FILE_APPEND | LOCK_EX);
30+
exit(0);
31+
}
32+
}
33+
34+
// Parent: wait for all children
35+
while (pcntl_wait($status) > 0);
36+
37+
$lines = array_filter(array_map('trim', file($tmpfile)));
38+
$unique = array_unique($lines);
39+
40+
// With 5 children and a 31-bit range, getting all identical values
41+
// from truly independent seeds is astronomically unlikely.
42+
if (count($unique) > 1) {
43+
echo "PASS: children produced different mt_rand values after fork\n";
44+
} else {
45+
echo "FAIL: all children produced the same mt_rand value: " . $lines[0] . "\n";
46+
}
47+
48+
@unlink($tmpfile);
49+
?>
50+
--EXPECT--
51+
PASS: children produced different mt_rand values after fork

main/main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "fopen_wrappers.h"
5252
#include "ext/standard/php_standard.h"
5353
#include "ext/date/php_date.h"
54+
#include "ext/random/php_random.h"
5455
#include "ext/random/php_random_csprng.h"
5556
#include "ext/random/php_random_zend_utils.h"
5657
#include "ext/opcache/ZendAccelerator.h"
@@ -1870,6 +1871,12 @@ PHPAPI void php_child_init(void)
18701871
{
18711872
refresh_memory_manager();
18721873
zend_max_execution_timer_init();
1874+
1875+
/* Force re-seeding of random engines in child process after fork(),
1876+
* otherwise the child inherits the parent's MT state and produces
1877+
* identical sequences. See GH-21351. */
1878+
RANDOM_G(mt19937_seeded) = false;
1879+
RANDOM_G(combined_lcg_seeded) = false;
18731880
}
18741881

18751882
/* {{{ php_request_startup */

0 commit comments

Comments
 (0)