-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix #78883: fgets(STDIN) fails on Windows #4952
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
Conversation
If a character file is detected as pipe, we have to set the Windows only flag `is_pipe_blocking`.
Is it possible to write a test for this somehow? |
I certainly would like to have a regression test for this (this bug should not have hit a GA version), but I'm afraid we can't have a PHPT, since as soon as STDIN is coming from a pipe, the bug would not trigger (STDIN must be FILE_TYPE_CHAR to exhibit the bug). Maybe @weltling or @KalleZ have an idea how this could be tested, nonetheless. |
It seems to me, that the detection is not quite correct in first place.
Making a pipe blocking by default also seems not the right way - it was especially done this way to avoid race conditions where reads would block forever due to the pipe buffering. Especially this concerns I'd suggest to rather to revisit the condition above to rework the handling for ensuring stdio is not seekable. Perhaps introduce a new flag like Thanks. |
Thanks @weltling! I fully agree that the naming is unfortunate (of course, a character device is not a pipe), but it seems to me that @nikic's fix (9ec61e4) is basically correct, since The only case where It might be sensible to do the renaming right away (e.g. |
@cmb69 thanks for checking. Especially for the windows implementation, it is inconsistent and will lead to issues on other ends. For example, anonymous/named pipes with regard to non blocking can use distinct handling. Separating these flags instead of overloading them will make this implementation future proof.
This is the exact point. Because it checks for Thanks. |
as for testing it, i suppose we could use proc_open() to start a cmd.exe and manipulate cmd.exe through stdin to start php -r 'var_dump(fgets(STDIN));' , give it a second to execute, then terminate it and inspect stdout? something like <?php
declare(strict_types=1);
$descriptorspec = array(
0 => array("pipe", "rb"),
1 => array("pipe", "wb"),
//2 => array("file", "stderr.txt", "ab")
);
$pipes=[];
$cmd=proc_open("cmd.exe",$descriptorspec,$pipes);
fwrite($pipes[0],"php -r ".escapeshellarg("var_dump(fgets(STDIN));")."\x0A"); // 0x0A should be enter key, but i can't actually test it now
sleep(1);
proc_terminate($proc);
fwrite($pipes[0],"exit\x0A");
fclose($pipes[0]);
$stdout=stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($proc);
var_dump( false===strpos($stdout,"bool(false)")); .. untested (the only windows system i can test on now has PHP installed through Cygwin, which is a linux-y build of php, not suitable for testing this), but something like that may work? (also idk how to actually send SIGINT to the child, something like ctrl+C, that's what i attempted with |
@divinity76, communicating via pipes won't exhibit the bug. |
@cmb69 well did some fiddling, this script prints bool(true) on php 7.4.0, and prints bool(false) on 7.4.1, probably because it identifies this bug:
|
Thanks for this great solution! I've added the test as 09e76cb. |
If a character file is detected as pipe, we have to set the Windows
only flag
is_pipe_blocking
.