classification
Title: Fatal python error when jumping into except clause
Type: crash Stage: patch review
Components: Interpreter Core, Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: louielu, ppperry, serhiy.storchaka, xdegaye
Priority: normal Keywords: patch

Created on 2017-07-17 21:24 by ppperry, last changed 2018-03-23 12:46 by serhiy.storchaka.

Pull Requests
URL Status Linked Edit
PR 6196 merged serhiy.storchaka, 2018-03-23 07:29
Messages (6)
msg298556 - (view) Author: (ppperry) Date: 2017-07-17 21:24
trying to execute the following code:
import sys
def trace(frame, event, arg):
    if event == "line" and frame.f_lineno > 12:
        frame.f_lineno = 12
        return None
    return trace
sys.settrace(trace)
def error():
    try:
        pass
    except:
        pass
    pass
    pass
error()
Produces a fatal error:
Fatal Python error: XXX block stack underflow

Current thread 0x00000af4 (most recent call first):
  File "jumpintoexception.py", line 12 in error
  File "jumpintoexception.py", line 15 in <module>
msg298572 - (view) Author: Louie Lu (louielu) * Date: 2017-07-18 03:53
You will need to use `dis` to see what actually done by bytecode.


$ ./python -m dis tests.py

Disassembly of <code object error at 0x7fbb69da5340, file "tests.py", line 8>:
  9           0 SETUP_EXCEPT             4 (to 6)

 10           2 POP_BLOCK
              4 JUMP_FORWARD            12 (to 18)

 11     >>    6 POP_TOP
              8 POP_TOP
             10 POP_TOP

 12          12 POP_EXCEPT
             14 JUMP_FORWARD             2 (to 18)
             16 END_FINALLY

 14     >>   18 LOAD_CONST               0 (None)
             20 RETURN_VALUE


this is the actual bytecode in `error()`.

When the eval loop hit the line 9, it will perform bytecode `SETUP_EXCEPT`, thus push a block into the blockstack. 
Your code in trace wrote that `and frame.f_lineno > 12`, thus it will run line 12 and perform POP_EXCEPT to pop out the blockstack.

then goto line 13, catch by trace if statement, f_lineno changed to 12, and perform `POP_EXCEPT` again, there isn't any block inside the blockstack, thus it will get a "XXX block stack underflow".
msg298817 - (view) Author: Xavier de Gaye (xdegaye) * (Python triager) Date: 2017-07-21 18:54
issue 17288 is related.
msg314272 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-03-22 16:45
This is fixed in 3.8.

Traceback (most recent call last):
  File "issue30953.py", line 15, in <module>
    error()
  File "issue30953.py", line 14, in error
    pass
  File "issue30953.py", line 14, in error
    pass
  File "issue30953.py", line 4, in trace
    frame.f_lineno = 12
ValueError: can't jump into or out of a 'finally' block
msg314291 - (view) Author: (ppperry) Date: 2018-03-22 20:46
... with a bad error message, because there are no finally blocks in the code
msg314307 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-03-23 12:46
New changeset 397466dfd905b5132f1c831cd9dff3ecc40b3218 by Serhiy Storchaka in branch 'master':
bpo-30953: Improve error messages and add tests for jumping (GH-6196)
https://github.com/python/cpython/commit/397466dfd905b5132f1c831cd9dff3ecc40b3218
History
Date User Action Args
2018-03-23 12:46:47serhiy.storchakasetmessages: + msg314307
2018-03-23 07:30:51serhiy.storchakasetversions: + Python 3.8, - Python 3.7
2018-03-23 07:29:40serhiy.storchakasetkeywords: + patch
stage: patch review
pull_requests: + pull_request5943
2018-03-22 20:46:11ppperrysetmessages: + msg314291
2018-03-22 16:45:58serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg314272
2017-07-21 18:54:38xdegayesetnosy: + xdegaye
messages: + msg298817
2017-07-18 03:53:19louielusetnosy: + louielu
messages: + msg298572
2017-07-17 21:24:58ppperrycreate