Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions ext/pcntl/tests/pcntl_fork_reseed_mt_rand.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
--TEST--
pcntl_fork() reseeds MT rand in child processes (GH-21351)
--EXTENSIONS--
pcntl
posix
--FILE--
<?php
/*
* When MT rand is seeded before fork(), child processes must not inherit
* the parent's MT state verbatim — each child should get a fresh seed
* so that mt_rand() / array_rand() / shuffle() produce different sequences.
*/

// Ensure MT rand is seeded before forking
mt_srand(42);
mt_rand();

$tmpfile = tempnam(sys_get_temp_dir(), 'pcntl_mt_');

$children = 5;
for ($i = 0; $i < $children; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("fork failed");
} else if ($pid == 0) {
// Child: generate a value and write it to the shared temp file.
// If reseeding works, children should not all produce the same value.
$val = mt_rand(0, PHP_INT_MAX);
file_put_contents($tmpfile, $val . "\n", FILE_APPEND | LOCK_EX);
exit(0);
}
}

// Parent: wait for all children
while (pcntl_wait($status) > 0);

$lines = array_filter(array_map('trim', file($tmpfile)));
$unique = array_unique($lines);

// With 5 children and a 31-bit range, getting all identical values
// from truly independent seeds is astronomically unlikely.
if (count($unique) > 1) {
echo "PASS: children produced different mt_rand values after fork\n";
} else {
echo "FAIL: all children produced the same mt_rand value: " . $lines[0] . "\n";
}

@unlink($tmpfile);
?>
--EXPECT--
PASS: children produced different mt_rand values after fork
7 changes: 7 additions & 0 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "fopen_wrappers.h"
#include "ext/standard/php_standard.h"
#include "ext/date/php_date.h"
#include "ext/random/php_random.h"
#include "ext/random/php_random_csprng.h"
#include "ext/random/php_random_zend_utils.h"
#include "ext/opcache/ZendAccelerator.h"
Expand Down Expand Up @@ -1870,6 +1871,12 @@ PHPAPI void php_child_init(void)
{
refresh_memory_manager();
zend_max_execution_timer_init();

/* Force re-seeding of random engines in child process after fork(),
* otherwise the child inherits the parent's MT state and produces
* identical sequences. See GH-21351. */
RANDOM_G(mt19937_seeded) = false;
RANDOM_G(combined_lcg_seeded) = false;
}

/* {{{ php_request_startup */
Expand Down
Loading