You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
assignee=Noneclosed_at=<Date2022-03-29.21:49:51.641>created_at=<Date2020-11-13.02:20:05.315>labels= ['type-feature', '3.10', 'docs']
title='KeyboardInterrupt should come with a warning'updated_at=<Date2022-03-29.21:49:51.640>user='https://github.com/benfogle'
This is related to bpo-29988, and I'm happy to move this to there. I made this a separate issue because this is a workaround, not a fix as was being discussed there. Also unlike bpo-29988, this is not restricted to context managers or finally blocks.
TL;DR: Raising exceptions from interrupt handlers (most notably KeyboardInterrupt) can wreak havoc in ways that are impossible to fix. This should be noted in the documentation, with a workaround.
I've attached a few example scripts that cause various strange behavior on Linux when a KeyboardInterrupt is raised at just the right time. There are likely many, many more possible examples:
sigint_condition_1.py: Cause a deadlock with threading.Condition
sigint_condition_2.py: Cause a double-release and/or notify on unacquired threading.Condition
sigint_tempfile.py: Cause NamedTemporaryFiles to not be deleted
sigint_zipfile.py: Cause ZipExtFile to corrupt its state
When a user presses Ctrl+C, a KeyboardInterrupt will be raised on the main thread at some later time. This exception may be raised after any bytecode, and most Python code, including the standard library, is not designed to handle exceptions that spring up from nowhere.
As a simple example, consider threading.Condition:
The KeyboardInterrupt could be raised just prior to return. In this case, __exit__ will never be called, and the underlying lock will remain acquired. A similar problem occurs if KeyboardInterrupt occurs at the start of __exit__.
This can be mitigated by attempting to catch a KeyboardInterrupt *absolutely everywhere*, but even then, it can't be fixed completely.
# it could happen here, in which case we should not unlockret=self._lock.__enter__()
# it could happen here, in which case we must unlockexceptKeyboardInterrupt:
# it could, in theory, happen again right here
raisereturnret# it could happen here, which is the same problem we had before
This is not restricted to context handlers or try/finally blocks. The zipfile module is a good example of code that is almost certain to enter an inconsistent state if a KeyboardInterrupt is raised while it's doing work:
self._readbuffer=b''# what happens if KeyboardInterrupt happens here?self._offset=0
Due to how widespread this is, it's not worth "fixing". (And honestly, it seems to be a rare problem in practice.) I believe that it would be better to clearly document that KeyboardInterrupt (or any exception propagated from a signal handler) may leave the system
in an inconsistent state. Complex or high reliability applications should avoid catching KeyboardInterrupt as a way of gracefully shutting down, and should prefer registering their own SIGINT handler. They should also avoid raising exceptions from signal handlers at all.