<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Fix fatal error reported on Windows when stdout fed to process which terminates before all output written"
   href="https://bugs.llvm.org/show_bug.cgi?id=49328">49328</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Fix fatal error reported on Windows when stdout fed to process which terminates before all output written
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>tools
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>llvm-objdump
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>jh7370.2008@my.bristol.ac.uk
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>I'm filing this against llvm-objdump, as that was the tool where this was first
noticed, but the issue is likely generic to most tools that produce stdout
output that might be redirected to the stdin of another process. If the other
process terminates before reading all the output (for example a tool like
"head"), then a crash in llvm-objdump is seen.

Example head.c:
#include <stdio.h>

static char buf[10240];
extern int atoi(const char *);

int main(int argc, char **argv)
{
  int i, n = atoi(argv[1]);
  for (i=0; i<n; i++) {
    fgets(buf, sizeof(buf), stdin);
    puts(buf);
  }
  return 0;
}

C:\Work>llvm-objdump -d test.elf | head 10
<a few lines of output>
LLVM ERROR: IO failure on output stream: invalid argument
PLEASE submit a bug report to <a href="https://bugs.llvm.org/">https://bugs.llvm.org/</a> and include the crash
backtrace.

Sometimes the backtrace doesn't appear after this, sometimes it does.

I debugged the behaviour. The error is reported because an error is stored in
the raw_fd_ostream for stdout, which hasn't been cleared, and as such a
report_fatal_error is triggered in the raw_fd_ostream's destructor. The error
is originally generated during a call to write_impl, and actually comes from
the call to ::write in that function. ::write sets errno to EINVAL, which is
the value stored in the stream's EC member.

After digging into the behaviour of ::write, I discovered the actual error
comes from an underlying call to WriteFile, after which the GetLastError()
return is ERROR_NO_DATA. Later, this value is translated into EINVAL for
placing in errno, which is not a particularly useful value for errno, as it
could represent a number of different failures. ERROR_NO_DATA on the other hand
is somewhat clearer - it appears to signal that the reader end of the pipe has
been closed when the writer attempts to write to it. I have searched around,
and the documentation for this behaviour is virtually non-existent, although
there are others who have confirmed that the error we see is seen by them in
the same situation too.

Fortunately, ERROR_NO_DATA is still returned by GetLastError by the time
::write returns. As such, we could detect this specific error value if errno is
EINVAL and do something different to what we do now. As it seems not
unreasonable for a process to hang up after it has received all the data it
wants, it might make sense to throw away all subsequent output if that error
has ever been detected. It doesn't seem right that we get a fatal error (i.e. a
crash) instead.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>