This is an archive of the discontinued LLVM Phabricator instance.

[llvm-symbolizer] Flush output on bad input
ClosedPublic

Authored by jhenderson on May 24 2019, 1:32 AM.

Details

Summary

One way of using llvm-symbolizer is to interactively within a process write a line from a parent process to llvm-symbolizer's stdin, and then read the output, then write the next line, read, etc. This worked as long as all the lines were good. However, this didn't work prior to this patch if any of the inputs were bad inputs, because the output is not flushed after a bad input, meaning the parent process is sat waiting for output, whilst llvm-symbolizer is sat waiting for input. This patch flushes the output after every invocation of symbolizeInput when reading from stdin. It also removes unnecessary flushing when llvm-symbolizer is not reading addresses from stdin, which should give a slight performance boost in these situations.

Diff Detail

Repository
rL LLVM

Event Timeline

jhenderson created this revision.May 24 2019, 1:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 24 2019, 1:32 AM

Make script python3 compatible by using bytes and flushing stdin.

I am a bit worried about the test which may, potentially, hang. Don't you think there should be any kind of a watchdog?

I am a bit worried about the test which may, potentially, hang. Don't you think there should be any kind of a watchdog?

Fair point, given that without the fix it does hang. Does lit have a built-in timeout option? Otherwise, I think the easiest thing to do is add a timeout to the test script or similar.

Add watchdog to timeout the test after 20 seconds.

I am a bit worried about the test which may, potentially, hang. Don't you think there should be any kind of a watchdog?

Fair point, given that without the fix it does hang. Does lit have a built-in timeout option? Otherwise, I think the easiest thing to do is add a timeout to the test script or similar.

I found lit does have a per-test timeout option, but it cannot be configured on an individual test level, only on a whole directory level, which I wasn't keen to do, so I've done a similar thing to what lit does in my test script.

ikudrin added inline comments.May 27 2019, 8:10 AM
test/tools/llvm-symbolizer/Inputs/flush-output.py
8

It looks like when process.kill() is executed, the main thread stops waiting, processes the rest and exits with the exit status 0.

The python documentation says:

Since exit() ultimately “only” raises an exception, it will only exit the process when called from the main thread, and the exception is not intercepted.

jhenderson marked an inline comment as done.Jun 3 2019, 3:58 AM
jhenderson added inline comments.
test/tools/llvm-symbolizer/Inputs/flush-output.py
8

I'm not sure what you're asking me to do here? This code causes llvm-symbolizer to end, rather than continuing to hang, and then the python script exits.

For reference, I verified that the test fails and only hangs for 20 seconds as expected, without the bug fix, and passes with the bug fix.

ikudrin added inline comments.Jun 3 2019, 4:37 AM
test/tools/llvm-symbolizer/Inputs/flush-output.py
8

Yes, the test fails, but not because the python script finishes with the exit code "1". The actual failure is that FileCheck cannot find all "CHECK" lines. Thus, the line sys.exit(1) is a bit of misleading.

If I understand your intention right, I would suggest rewriting the script in the following way:

exit_status = 0

def kill_subprocess(process):
    global exit_status
    exit_status = 1
    process.kill()

cmd = ...
...
sys.exit(exit_status)
jhenderson marked an inline comment as done.Jun 4 2019, 7:15 AM
jhenderson added inline comments.
test/tools/llvm-symbolizer/Inputs/flush-output.py
8

Oh, I didn't realise that sys.exit() doesn't do anything in a subthread. process.kill() ends up causing an IOError later on, but I think this can be worked around by using a try/except block. I'll update the diff in a bit to show what I mean.

jhenderson updated this revision to Diff 202937.Jun 4 2019, 7:31 AM

Switch to using os._exit() instead of sys.exit(). This terminates the process even from the subthread. There's no need to do any cleanup etc, so this should be sufficient for our test.

(I originally was going to put a try/except block around the stdin/stdout reading/writing blocks, but on second thoughts, I don't think that's necessary).

ikudrin accepted this revision.Jun 4 2019, 7:51 AM

LGTM

This revision is now accepted and ready to land.Jun 4 2019, 7:51 AM
jhenderson updated this revision to Diff 202944.Jun 4 2019, 8:06 AM

Reinstate 20s timeout back up from 2s (used for experimentation).

jhenderson updated this revision to Diff 202947.Jun 4 2019, 8:23 AM

Re-add FileCheck run accidentally removed in previous version.

This revision was automatically updated to reflect the committed changes.