Skip to content

Commit b60872b

Browse files
bug #31568 [Process] Fix infinite waiting for stopped process (mshavliuk)
This PR was squashed before being merged into the 3.4 branch (closes #31568). Discussion ---------- [Process] Fix infinite waiting for stopped process | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #31548 | License | MIT ### Description Add a regression test `Symfony\Component\Process\Tests\ProcessTest:testWaitStoppedDeadProcess` to reproduce the related bug #31548 . It consists of one file `ErrorProcessInitiator.php`, which executes as another process because otherwise if `Process::wait()` goes in an infinite loop (which is test checks) it will be impossible to handle it and stop test correctly. The second commit contains bug fix, which is only `$this->checkTimeout();` call, that prevents infinite loop. Commits ------- 6b9ee1e [Process] Fix infinite waiting for stopped process
2 parents ae30af9 + 6b9ee1e commit b60872b

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ public function wait(callable $callback = null)
427427
} while ($running);
428428

429429
while ($this->isRunning()) {
430+
$this->checkTimeout();
430431
usleep(1000);
431432
}
432433

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Process\Tests;
13+
14+
use Symfony\Component\Process\Exception\ProcessTimedOutException;
15+
use Symfony\Component\Process\Process;
16+
17+
require \dirname(__DIR__).'/vendor/autoload.php';
18+
19+
list('e' => $php) = getopt('e:') + ['e' => 'php'];
20+
21+
try {
22+
$process = new Process("exec $php -r \"echo 'ready'; trigger_error('error', E_USER_ERROR);\"");
23+
$process->start();
24+
$process->setTimeout(0.5);
25+
while (false === strpos($process->getOutput(), 'ready')) {
26+
usleep(1000);
27+
}
28+
$process->signal(SIGSTOP);
29+
$process->wait();
30+
31+
return $process->getExitCode();
32+
} catch (ProcessTimedOutException $t) {
33+
echo $t->getMessage().PHP_EOL;
34+
35+
return 1;
36+
}

src/Symfony/Component/Process/Tests/ProcessTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,15 @@ public function testEnvArgument()
15511551
$this->assertSame($env, $p->getEnv());
15521552
}
15531553

1554+
public function testWaitStoppedDeadProcess()
1555+
{
1556+
$process = $this->getProcess(self::$phpBin.' '.__DIR__.'/ErrorProcessInitiator.php -e '.self::$phpBin);
1557+
$process->start();
1558+
$process->setTimeout(2);
1559+
$process->wait();
1560+
$this->assertFalse($process->isRunning());
1561+
}
1562+
15541563
/**
15551564
* @param string $commandline
15561565
* @param string|null $cwd

0 commit comments

Comments
 (0)