classification
Title: Potential race condition in exceptions
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.3
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Sworddragon, ezio.melotti, neologix, r.david.murray
Priority: normal Keywords:

Created on 2013-08-26 06:11 by Sworddragon, last changed 2013-08-28 11:42 by Sworddragon. This issue is now closed.

Files
File name Uploaded Description Edit
race_condition_fast.py Sworddragon, 2013-08-26 06:11 Example of a very rare race condition
race_condition_slow.py Sworddragon, 2013-08-26 06:12 Example of a reproducible race condition
Messages (11)
msg196181 - (view) Author: (Sworddragon) Date: 2013-08-26 06:11
On a try/except-block if an exception raises (for example KeyboardInterrupt) the except block could cause another exception and if this block tries to catch it too the nested except block could cause another exception again. This goes into an unlimited recursion.

In the attachments is an example of such a problem (race_condition_fast.py). But as it is called a "race condition" it is nearly impossible to reproduce it by a human. For this case I have adjusted the example (race_condition_slow.py). The third CTRL + C will cause a KeyboardInterrupt.
msg196182 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2013-08-26 06:29
> The third CTRL + C will cause a KeyboardInterrupt.

This is expected.  The first ctrl+c interrupts the first sleep and goes in the second try, executing the second sleep.  The second ctrl+c interrupts the second sleep and goes in the second except where it finds the third sleep.  Here a third ctrl+c will interrupt the sleep and since this line is not in a try block nothing will catch the KeyboardInterrupt.

Are you saying that if the user keeps hitting ctrl+c you would need an endless chain of nested try/except in order to catch them all?
msg196183 - (view) Author: (Sworddragon) Date: 2013-08-26 06:32
> Are you saying that if the user keeps hitting ctrl+c you would need an endless chain of nested try/except in order to catch them all?

Correct. For example if I want to show the user the message "Aborted" instead of a huge exception if he hits CTRL + C another KeyboardInterrupt could appear.
msg196215 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-08-26 15:47
Then you catch KeyboardInterrupt and present your alternate text.  I'm not following what the problem is. In particular, once you've caught KeyboardInterrupt, a second ctl-C *should* cause a normal program break, otherwise you've locked the user into a infinite loop he can't get out of if your program logic is wrong.
msg196221 - (view) Author: (Sworddragon) Date: 2013-08-26 16:16
The problem is simple: It is not possible to catch every exception in an application. Even if you try to print a message and exit on an exception it is always possible that the user will see a traceback.
msg196225 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-08-26 16:48
I wonder if you could achieve what you want (which I always hope programs I use never do[*]) by writing your own signal handler.

In any case, I don't believe there is a bug here.  This is working as designed.

[*] There are many times I have found myself leaning on ctl-C on autorepeat hoping that the ctl-c will happen at a point where the application isn't catching it, so that I can get the darn thing to abort.  I realize you are proposing to do this only to then do the abort...but what if there is a bug in your code?  I'd *much* rather see a traceback than have to fall back to 'kill'.  At least with the traceback I know the interpreter has had a chance to clean up.
msg196265 - (view) Author: (Sworddragon) Date: 2013-08-27 06:48
> but what if there is a bug in your code?

Bugs in a python application can be fixed by the user while a specific behavior of the interpreter can't.

Maybe you are also thinking in the wrong direction. Nobody wants a solution that traps the user forever. Also KeyboardInterrupt is not the only problem that is affected by this race condition (but it is the best example to demonstrate it).


But I have made some thoughts about a potential solution (maybe it needs fine-tuning, depending on the python developing-policies or if I have overlooked something):

The idea contains overloading on a try/except-block. We will have the old (current) except block that acts as we know it and we will have a function-like except block "except(string_message, int_exitcode):". The function-like except block is a policy for any nested exception. Instead of triggering the nested exception it will print the first argument to stderr and exit with the second argument. While the interpreter is doing this as a built-in call it disables any potential exception-triggering in this time. This solution will eliminate the race condition without catching the user in an infinite recursion. What do you think of this idea?
msg196283 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-08-27 12:46
Unless I'm completely misunderstanding (which I don't think I am), this is not a race condition, it is how the language is designed to operate.  The change you are proposing is a language-design level change that would require a PEP.  The appropriate place to discuss this the is the python-ideas list.

I'm going to close this issue.  If you get a positive response on python-ideas, you can reopen it with a link to the discussion.
msg196289 - (view) Author: (Sworddragon) Date: 2013-08-27 13:45
> Unless I'm completely misunderstanding (which I don't think I am), this is not a race condition, it is how the language is designed to operate.

If it is intended not to be able to catch all exceptions and prevent a traceback being showed this should be indeed a PEP.
msg196348 - (view) Author: Charles-Fran├žois Natali (neologix) * (Python committer) Date: 2013-08-28 05:25
> If it is intended not to be able to catch all exceptions
> and prevent a traceback being showed this should be indeed a PEP.

You may want to have a look at sys.excepthook.
msg196376 - (view) Author: (Sworddragon) Date: 2013-08-28 11:42
> You may want to have a look at sys.excepthook.

This would not solve the race condition.
History
Date User Action Args
2013-08-28 11:42:42Sworddragonsetmessages: + msg196376
2013-08-28 05:25:47neologixsetnosy: + neologix
messages: + msg196348
2013-08-27 13:45:50Sworddragonsetmessages: + msg196289
2013-08-27 12:46:59r.david.murraysetstatus: open -> closed
resolution: not a bug
messages: + msg196283

stage: resolved
2013-08-27 06:48:24Sworddragonsetmessages: + msg196265
2013-08-26 16:48:47r.david.murraysetmessages: + msg196225
2013-08-26 16:16:34Sworddragonsetmessages: + msg196221
2013-08-26 15:47:27r.david.murraysetnosy: + r.david.murray
messages: + msg196215
2013-08-26 06:32:52Sworddragonsetmessages: + msg196183
2013-08-26 06:29:06ezio.melottisetnosy: + ezio.melotti
messages: + msg196182
2013-08-26 06:12:37Sworddragonsetfiles: + race_condition_slow.py
2013-08-26 06:11:49Sworddragoncreate