From 7f00abc36be15f398fa3ecf9f4e5283509c34a00 Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Tue, 27 Jul 2021 12:59:55 -0400 Subject: [PATCH] jobserver: fix rare race condition in previous timer-exception workaround. We have to clear the setitimer *before* leaving the try/except clause, or the timer might fire between the try/except and the try/finally, leaking a TimeoutError. Reported-by: Denton Gentry --- redo/jobserver.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/redo/jobserver.py b/redo/jobserver.py index 86eea3c..6dc30b6 100644 --- a/redo/jobserver.py +++ b/redo/jobserver.py @@ -178,17 +178,17 @@ def _try_read(fd, n): signal.setitimer(signal.ITIMER_REAL, 0.01, 0.01) # emergency fallback try: b = os.read(fd, 1) - except TimeoutError: + finally: + signal.setitimer(signal.ITIMER_REAL, 0, 0) + signal.signal(signal.SIGALRM, oldh) + except TimeoutError: + return None # try again + except OSError as e: + if e.errno in (errno.EAGAIN, errno.EINTR): + # interrupted or it was nonblocking return None # try again - except OSError as e: - if e.errno in (errno.EAGAIN, errno.EINTR): - # interrupted or it was nonblocking - return None # try again - else: - raise - finally: - signal.setitimer(signal.ITIMER_REAL, 0, 0) - signal.signal(signal.SIGALRM, oldh) + else: + raise return b