mstorsjo/msvc-wine

Problem with closing piped output due to msvctricks.exe

mstorsjo opened this issue · 1 comments

CC @huangqinjin

Since the introduction of the msvctricks.exe binary, closing the output pipe of the compiler causes hangs.

To reproduce:

$ echo '#include <vector>' > file.cpp
$ cl -E file.cpp | less

Within less, type q to stop reading the input (after only consuming a screenful of output, from the preprocessing output which is large enough to block the pipe buffers). Normally I would expect all processes to exit at this point (possibly with some complaints due to the broken pipe). With msvctricks.exe in place, I instead get a hang. If I remove msvctricks.exe so that this only uses the redirections done in wine-msvc.sh, this works as expected.

I reproduced the issue.

demo.cpp

#include <stdio.h>
int main(int argc, char* argv[])
{
    FILE* f = argv[1] ? fopen(argv[1], "w") : stdout;
    for (int i = 0; i < 100000; ++i)
        fprintf(f, "%d\n", i);
    return 119;
}
g++ demo.cpp -o demo
/opt/msvc/bin/x64/cl demo.cpp

Use stdout

$ ./demo | head -n1 >/dev/null; echo "${PIPESTATUS[@]}"
141 0
$ wine64 demo.exe | head -n1 >/dev/null; echo "${PIPESTATUS[@]}"
119 0
  • Linux app exits with 141 = 128 + SIGPIPE(13).
  • Win32 app ignores SIGPIPE and exits normally.

Use FIFO

$ mkfifo fifo
$ { cat fifo || echo "cat $?">&2  &  ./demo fifo || echo "demo $?">&2; } | head -n1 >/dev/null
cat 141
demo 141
$ { cat fifo || echo "cat $?">&2  &  wine64 demo.exe fifo || echo "demo $?">&2; } | head -n1 >/dev/null
cat 141
<hangs>
$ { cat fifo || echo "cat $?">&2  &  wine64 demo.exe >fifo || echo "demo $?">&2; } | head -n1 >/dev/null
cat 141
demo 119

Wine handles SIGPIPE differently for stdout and other fds (logs are from strace output):

  • SIGPIPE is silently ignored on stdout and app doesn't get terminated.
    write(7, "0\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10"..., 5119) = 5119
    write(7, "038\r\n1039\r\n1040\r\n1", 18) = 18
    write(7, "041\r\n1042\r\n1043\r\n1044\r\n1045\r\n104"..., 4915) = -1 EPIPE (Broken pipe)
    --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17632, si_uid=1000} ---
    write(7, "61861\r\n1862\r\n1863\r\n1864\r\n1865\r\n1"..., 4915) = -1 EPIPE (Broken pipe)
    --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17632, si_uid=1000} ---
    ...
    
  • app is blocking on poll after the other end of the pipe is closed:
    ...
    write(11, "233\r\n9234\r\n9235\r\n9236\r\n9237\r\n923"..., 4906) = 4906
    write(11, "3\r\n10044\r\n10045\r\n10046\r\n10047\r\n1"..., 4779) = 683
    poll([{fd=11, events=POLLOUT}], 1, -1) 
    

The proposed solution is to manually kill wine after cat exits.