From 3272a143af40a999bea853397fca36683f4ef68b Mon Sep 17 00:00:00 2001 From: NickSdot Date: Tue, 28 Jul 2026 20:29:30 +0700 Subject: [PATCH 1/2] Parallelize new_oom subprocesses --- Zend/tests/new_oom.phpt | 100 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/Zend/tests/new_oom.phpt b/Zend/tests/new_oom.phpt index 6d4ba3d760b4..7f891f233617 100644 --- a/Zend/tests/new_oom.phpt +++ b/Zend/tests/new_oom.phpt @@ -1,5 +1,5 @@ --TEST-- -Test OOM on new of each class +Test OOM on new of each instantiable class --SKIPIF-- /dev/null'); + if (!is_string($processCount)) { + return 1; + } + + $processCount = filter_var(trim($processCount), FILTER_VALIDATE_INT, [ + 'options' => ['min_range' => 1], + ]); + + return $processCount === false ? 1 : min($processCount, 4); +} + +function startOomTest(string $php, string $file, string $class): ?array +{ + $output = tmpfile(); + if ($output === false) { + echo "Class $class failed\nUnable to create output file\n"; + return null; + } + + $process = proc_open( + [$php, '--no-php-ini', $file, $class], + [ + 0 => ['null'], + 1 => $output, + 2 => ['redirect', 1], + ], + $pipes, + ); + if (!is_resource($process)) { + fclose($output); + echo "Class $class failed\nUnable to start process\n"; + return null; + } + + return [ + 'class' => $class, + 'output' => $output, + 'process' => $process, + ]; +} + +function finishOomTest(array $test): bool +{ + $status = proc_get_status($test['process']); + if ($status['running']) { + return false; + } + + proc_close($test['process']); + rewind($test['output']); + $output = stream_get_contents($test['output']); + fclose($test['output']); + + if ($status['signaled']) { + echo "Class {$test['class']} failed\n"; + echo "Process terminated by signal {$status['termsig']}\n"; + } elseif ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+\nStack trace:\n(#[0-9]+ [^\r\n]+\n)+$)', $output) !== 1) { + echo "Class {$test['class']} failed\n"; + echo $output, "\n"; + } + + return true; +} + $file = __DIR__ . '/new_oom.inc'; $php = PHP_BINARY; +$classes = array_filter( + get_declared_classes(), + static fn(string $class): bool => (new ReflectionClass($class))->isInstantiable(), +); +$tests = []; +$processCount = getOomProcessCount(); -foreach (get_declared_classes() as $class) { - $output = shell_exec("$php --no-php-ini $file $class 2>&1"); - if ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+\nStack trace:\n(#[0-9]+ [^\r\n]+\n)+$)', $output) !== 1) { - echo "Class $class failed\n"; - echo $output, "\n"; +while ($classes || $tests) { + while ($classes && count($tests) < $processCount) { + $class = array_shift($classes); + $test = startOomTest($php, $file, $class); + if ($test !== null) { + $tests[] = $test; + } + } + + $testFinished = false; + foreach ($tests as $index => $test) { + if (finishOomTest($test)) { + unset($tests[$index]); + $testFinished = true; + } + } + if (!$testFinished) { + usleep(1000); } } From caef944cef22e1ccf547483078075dc220953a19 Mon Sep 17 00:00:00 2001 From: NickSdot Date: Thu, 30 Jul 2026 22:59:09 +0700 Subject: [PATCH 2/2] review: replaced optional Filter dependency in OOM worker detection --- Zend/tests/new_oom.phpt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Zend/tests/new_oom.phpt b/Zend/tests/new_oom.phpt index 7f891f233617..8d36a83f101a 100644 --- a/Zend/tests/new_oom.phpt +++ b/Zend/tests/new_oom.phpt @@ -17,11 +17,11 @@ function getOomProcessCount(): int return 1; } - $processCount = filter_var(trim($processCount), FILTER_VALIDATE_INT, [ - 'options' => ['min_range' => 1], - ]); - - return $processCount === false ? 1 : min($processCount, 4); + $processCount = trim($processCount); + if (preg_match('/^[1-9][0-9]*$/D', $processCount) !== 1) { + return 1; + } + return min((int) $processCount, 4); } function startOomTest(string $php, string $file, string $class): ?array