Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Console QuestionHelper autocompelte does not restore stty on SIGINT #27786

Closed
rtek opened this issue Jun 30, 2018 · 3 comments
Closed

Console QuestionHelper autocompelte does not restore stty on SIGINT #27786

rtek opened this issue Jun 30, 2018 · 3 comments

Comments

@rtek
Copy link
Contributor

rtek commented Jun 30, 2018

Symfony version(s) affected: 4.1

Description
If the user sends a SIGINT (CTRL+C) during the autocomplete phase of question ask, the stty will not be restored to its original state. This means that the console will not echo as the user types until they type stty echo (which they cannot see).

How to reproduce
This applies to linux and windows but I only created a test for windows.

This is a disaster of a test case because I needed to mock out shell_exec & stty somehow... 🤷‍♂️

//as part of QuestionHelperTest
    /**
     * @runInSeparateProcess
     */
    public function testAskWithAutocompleteRestoresSttyOnSigInt()
    {
        if(DIRECTORY_SEPARATOR === '/') {
            $this->markTestSkipped('Must run in windows');
        }

        $tempDir = getcwd().'/__temp';
        @mkdir($tempDir);
        chdir($tempDir);

        //this writes the stty arguments to the test file for inspection and returns a mode=restored for stty -g
        $sttyMock = "@echo off\r\necho \"%0 %*\" > stty.out\r\necho|set /p dummy=restored";
        file_put_contents('stty.bat', $sttyMock);

        register_shutdown_function(function() use ($tempDir) {
            $this->assertContains('restored', file_get_contents($tempDir . '/stty.out'));
        });

        $dialog = new QuestionHelper();
        $question = new Question('How are you');
        $question->setAutocompleterValues(array('Good', 'Bad'));

        //force an exit when ! is detected in the input stream
        $output = new class extends Output {
            protected function doWrite($message, $newline)
            {
                if($message === '!') {
                    exit(1); //simulate a CTRL-C
                }
            }
        };

        $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('ABC!123')), $output, $question);
    }
1) Symfony\Component\Console\Tests\Helper\QuestionHelperTest::testAskWithAutocompleteRestoresSttyOnSigInt
PHPUnit\Framework\Exception: PHP Fatal error:  Uncaught Failed asserting that '"stty -icanon -echo" \r\n
' contains "restored".

Possible Solution
register_shutdown_function can be used to add a handler that will restore the stty mode if it is not restored successfully. I looked into pcntl_signal but it does not allow multiple handlers.

SIGINT seems to cause shutdown functions to not be called?

@rtek
Copy link
Contributor Author

rtek commented Jul 1, 2018

After further review I dont know if this can be fixed on windows since i cant find a way to hook into SIGINT.

For what its worth one can wrap the PHP call to restore the stty mode.

#!/usr/bin/env bash
STTY_MODE=$(stty -g)
trap "stty ${STTY_MODE}" SIGINT
php app.php $@

@Simperfit
Copy link
Contributor

@rtek can you test with last master ? we made some changes about this.

@chalasr
Copy link
Member

chalasr commented Apr 7, 2019

Fixed by #30883.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants