-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Flush stdout when control returns to shell #10861
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
|
I'd mention it: "Standard output is flushed after external commands exit, in an attempt to reduce interleaving their output with the prompt (:issue: |
This prevents kernel-buffered stdout contents from being written to the terminal after the prompt itself, which can happen when the external process is terminated with a signal and hasn't executed the libc/runtime-provided exit handlers that flush stdout. While it is possible for a libc-less application to exit normally without flushing the stdout fd, the only way for "normal" applications to bypass the atexit handlers would be to exit via abort() (i.e. SIGABRT) or in response to some other signal; so we currently only flush stdout in response to such an exit to reduce syscall overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't make any sense to me. In my understanding, std::io::stdout().flush() flushes Rust's internal buffer. Because this is in-process, there is no way for an external command, such as afl-fuzz, to append to that buffer, so there is nothing to flush, so I would not expect this to do anything at all.
If there is something to flush, then it ought to have been flushed before the external command ran!
Can you please write a command line program that demonstrates this in action? afl-fuzz doesn't seem available on Apple Silicon.
|
You're right; I think I ran into a change in timing that resulted in the "corrected" behavior. I was thinking in terms of Are race conditions here inevitable? |
|
I think some race conditions are inevitable, especially with curses-style apps such as afl-fuzz. For example, if the app moves the cursor to some point on the screen and then dies, then fish will inherit a weird cursor position and I can see how that might screw up the prompt - though I would expect the If you want to pursue this, it would be useful to write a custom tool that reproduces this, so we can explore more. |
|
It actually reproduces when afl is still starting up and only producing a colorized log of text to stdout with no real tui to speak of, but it must be using absolute positioning ansi escapes or similar because regular stdout is strictly linear. I wonder if I can just record and replay the output of afl instead of trying to independently reproduce the race. |
|
|
|
Thanks, that's useful. Probably have to use socat to trick it into thinking its running in a terminal, though. |
|
I wrote this last week but never hit submit: I didn't need to use Here's a sample (replay with Looking at the output with One obvious answer is to set |
This prevents kernel-buffered stdout contents from being written to the terminal after the prompt itself, which can happen when the external process is terminated with a signal and hasn't executed the libc/runtime-provided exit handlers that flush stdout.
Screenshots of afl-fuzz being terminated by
^Cbefore and after the change:Before:
After:
I tried to minimize any performance impact by trying to reduce the number of times this is called (by placing it as high up as possible, but bubbling up reap status) and by not performing the call in non-interactive mode (where fish shouldn't be painting to the shell bypassing stdout). stderr isn't flushed because it's typically unbuffered.
Let me know if you think this should be included in the changelog afterwards.
TODOs: