Closed tornaria closed 2 years ago
It might be convenient to change all uses of fprintf()
inside the signal handler by write()
; this is the minimal change required to pass all current doctests.
There are more fprintf
s in this file, did you check that the rest are harmless?
There are more
fprintf
s in this file, did you check that the rest are harmless?
No, I just patched out the one that was causing the bad doctest for me.
If you are ok with this change, I can go and look for other instances inside the signal handlers. At least the ones that are compiled when debug is disabled (the ones for debug tend to have more parameters so they are more work to translate, although it can also be done).
I don't know how to actually force the failure; it just happens with my particular version of python + glibc on 32 bit, and I wouldn't know how to make other instances fail. Also, it's kind of weird that other fprintf calls inserted here and there might randomly fix the issue as internal stdio state gets somehow cleared (moreover, gcc changes fprintf without optional arguments to fwrite which doesn't seem to have the problem, although the standard still forbids it).
Maybe it's possible to replace fprintf by a stub that checks and warns on reentrancy.
Thanks for the changes, I bumped the version number and added a note in the README.
This failure is 100% reproducible on void linux i686 (glibc 2.32).
The example is in the function
test_bad_str()
in the filetests.pyx
. The test pases a bad string tosig_str()
and then raisesSIGILL
. The signal handler eventually raises a Python exception which in turn raises aSIGSEGV
when accessing the bad string. An error message is expected, but that doesn't happen.Presumably the segfault happens inside some stdio function which leaves stdio buffers in an inconsistent state so the latter
fprintf
doesn't work properly. Fromsignal-safety(7)
:We fix this by replacing the
fprintf
by calls towrite
, which is async-signal-safe according to POSIX.