ionelmc/python-manhole — pull request #29 by nirs (2014-10-18 15:23:26+00:00)
Title: Avoid deadlock after fork triggered by manhole.cry()

On python 3 and pypy, manhole may trigger a deadlock by writing to
stderr while fork is invoked by user code. With correct timing, the
child finds stderr lock in locked state, and deadlock when tyring to
write to stderr in cry().

This issue can be reproduced when running the fork_exec tests using
pypy:

manhole.install() # cry() in manhole thread
subprocess.call(['true']) # cry() after fork

It can also be reproduced by this code, with both python3 and pypy:

import os
import sys
import threading

def run():
sys.stderr.write("in parent thread\n")

threading.Thread(target=run).start()
pid = os.fork()
if pid:
os.waitpid(pid, 0)
else:
sys.stderr.write("in child\n")

This patch adds a _CRY_LOCK lock, and ensures that it is held while
writing to stderr or forking, and that _CRY_LOCK is released in the
child after forking.

If forking functions are not patched, this change does not have any
effect. We should consider always patching fork functions, even when we
don't want to reinstall manhole, only to avoid this possible deadlock.