Skip to content

Commit

Permalink
bug #31568 [Process] Fix infinite waiting for stopped process (mshavl…
Browse files Browse the repository at this point in the history
…iuk)

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
  • Loading branch information
nicolas-grekas committed May 22, 2019
2 parents ae30af9 + 6b9ee1e commit b60872b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Component/Process/Process.php
Expand Up @@ -427,6 +427,7 @@ public function wait(callable $callback = null)
} while ($running);

while ($this->isRunning()) {
$this->checkTimeout();
usleep(1000);
}

Expand Down
36 changes: 36 additions & 0 deletions src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Process\Tests;

use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Process;

require \dirname(__DIR__).'/vendor/autoload.php';

list('e' => $php) = getopt('e:') + ['e' => 'php'];

try {
$process = new Process("exec $php -r \"echo 'ready'; trigger_error('error', E_USER_ERROR);\"");
$process->start();
$process->setTimeout(0.5);
while (false === strpos($process->getOutput(), 'ready')) {
usleep(1000);
}
$process->signal(SIGSTOP);
$process->wait();

return $process->getExitCode();
} catch (ProcessTimedOutException $t) {
echo $t->getMessage().PHP_EOL;

return 1;
}
9 changes: 9 additions & 0 deletions src/Symfony/Component/Process/Tests/ProcessTest.php
Expand Up @@ -1551,6 +1551,15 @@ public function testEnvArgument()
$this->assertSame($env, $p->getEnv());
}

public function testWaitStoppedDeadProcess()
{
$process = $this->getProcess(self::$phpBin.' '.__DIR__.'/ErrorProcessInitiator.php -e '.self::$phpBin);
$process->start();
$process->setTimeout(2);
$process->wait();
$this->assertFalse($process->isRunning());
}

/**
* @param string $commandline
* @param string|null $cwd
Expand Down

0 comments on commit b60872b

Please sign in to comment.