Skip to content

Commit 4a2ba8e

Browse files
meshulamumn-meshulam
authored andcommitted
Defer registering SIGCONT handler until UnixConsole is actually used
Related: gh-161254
1 parent 3945eaf commit 4a2ba8e

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

‎Lib/_pyrepl/unix_console.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,6 @@ def _my_getstr(cap: str, optional: bool = False) -> bytes | None:
267267
)
268268
self.cursor_visible = True
269269

270-
signal.signal(signal.SIGCONT, self._sigcont_handler)
271-
272270
def _sigcont_handler(self, signum, frame):
273271
self.restore()
274272
self.prepare()
@@ -505,6 +503,7 @@ def prepare(self) -> None:
505503

506504
try:
507505
self.old_sigwinch = signal.signal(signal.SIGWINCH, self.__sigwinch)
506+
signal.signal(signal.SIGCONT, self._sigcont_handler)
508507
except ValueError:
509508
pass
510509

@@ -515,6 +514,9 @@ def restore(self) -> None:
515514
Restore the console to the default state
516515
"""
517516
trace("unix.restore")
517+
if not hasattr(self, "_UnixConsole__svtermstate"):
518+
# prepare() never ran, so there is nothing to restore
519+
return
518520
self.__write(ANSIColors.RESET)
519521
self.__disable_bracketed_paste()
520522
self.__maybe_write_code(self._rmkx)
@@ -533,6 +535,11 @@ def restore(self) -> None:
533535
raise e
534536
del self.old_sigwinch
535537

538+
try:
539+
signal.signal(signal.SIGCONT, signal.SIG_DFL)
540+
except ValueError:
541+
pass
542+
536543
def push_char(self, char: int | bytes) -> None:
537544
"""
538545
Push a character to the console event queue.

‎Lib/test/test_pyrepl/test_unix_console.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,26 @@ def test_restore_in_thread(self, _os_write):
401401
thread.start()
402402
thread.join() # this should not raise
403403

404+
@unittest.skipIf(not hasattr(signal, "SIGCONT"), "needs signal.SIGCONT")
405+
def test_sigcont_is_armed_only_by_prepare(self, _os_write):
406+
# gh-161254: A console must install its SIGCONT handler only while it
407+
# owns the terminal, i.e. between prepare() and restore().
408+
console = UnixConsole(term="xterm")
409+
self.assertEqual(signal.getsignal(signal.SIGCONT), signal.SIG_DFL)
410+
console.prepare()
411+
self.assertEqual(
412+
signal.getsignal(signal.SIGCONT), console._sigcont_handler
413+
)
414+
console.restore()
415+
self.assertEqual(signal.getsignal(signal.SIGCONT), signal.SIG_DFL)
416+
417+
@unittest.skipIf(not hasattr(signal, "SIGCONT"), "needs signal.SIGCONT")
418+
def test_restore_without_prepare(self, _os_write):
419+
# gh-161254
420+
console = UnixConsole(term="xterm")
421+
self.assertFalse(hasattr(console, "_UnixConsole__svtermstate"))
422+
console.restore() # this should not raise
423+
404424

405425
@unittest.skipIf(sys.platform == "win32", "No Unix console on Windows")
406426
class TestUnixConsoleEIOHandling(TestCase):

0 commit comments

Comments
 (0)