-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cannot jump from a 'return' or 'exception' trace event #61490
Comments
On python 3.3 and the default branch, the jump from a 'return' fails although This problem does not occur with python 2.7. $ python return.py
> /tmp/return.py(8)<module>()
-> foo()
(Pdb) break 5
Breakpoint 1 at /tmp/return.py:5
(Pdb) continue
> /tmp/return.py(5)foo()
-> lineno = 5
(Pdb) step
--Return--
> /tmp/return.py(5)foo()->None
-> lineno = 5
(Pdb) jump 4
> /tmp/return.py(4)foo()->None
-> lineno = 4
(Pdb) where
/tmp/return.py(8)<module>()
-> foo()
> /tmp/return.py(4)foo()->None
-> lineno = 4
(Pdb) step
--Return--
> /tmp/return.py(8)<module>()->None
-> foo()
(Pdb) |
Oops, it occurs too with python 2.7. |
Nosying Benjamin Peterson who knows frame_setlineno (bpo-14612) and nosying This problem occurs also when setting f_lineno from an exception debug event. One may crash the interpreter (or get a "SystemError: unknown opcode") when the $ python /tmp/jump.py
> /tmp/jump.py(7)<module>()
-> for i in gen():
(Pdb) step
--Call--
> /tmp/jump.py(1)gen()
-> def gen():
(Pdb) step
> /tmp/jump.py(2)gen()
-> for i in range(1):
(Pdb) step
> /tmp/jump.py(3)gen()
-> yield i
(Pdb) step
--Return--
> /tmp/jump.py(3)gen()->0
-> yield i
(Pdb) jump 2
> /tmp/jump.py(2)gen()->0
-> for i in range(1):
(Pdb) step
> /tmp/jump.py(8)<module>()
-> lineno = 8
(Pdb) step
> /tmp/jump.py(7)<module>()
-> for i in gen():
(Pdb) step
--Call--
> /tmp/jump.py(2)gen()->0
-> for i in range(1):
(Pdb) step
Segmentation fault |
The proposed patch fixes the problem:
To summarize the proposed fixes on f_lineno accessors:
|
Must add for completeness that f_lineno must be valid within a return trace |
Python 3.5 is still crashing with this test: $ python jump.py
> jump.py(7)<module>()
-> for i in gen():
(Pdb) break 3
Breakpoint 1 at jump.py:3
(Pdb) continue
> jump.py(3)gen()
-> yield i
(Pdb) step
--Return--
> jump.py(3)gen()->0
-> yield i
(Pdb) jump 2
> jump.py(2)gen()->0
-> for i in range(1):
(Pdb) continue
Segmentation fault (core dumped) It is true that frame_setlineno() assumes incorrectly that f->f_stacktop is not NULL, but the reason of the crash or of the "SystemError: unknown opcode" is that PyEval_EvalFrameEx() expects on its invocation f->f_lasti to refer to the index of the last instruction executed and sets (and assumes this instruction does not have argument) 'next_instr' accordingly to the next byte, while by jumping to line 2 we set f->f_lasti to zero and 'SETUP_LOOP', the opcode at this index, has an argument. The attached patch is a slight improvement over the last one. |
Do you mind to create a PR from your patch Xavier? The code of the f_lineno setter was changed in the master branch, so that it is better to create a PR for the 3.7 branch and later port it to master. |
Example in msg183254 doesn't crash Python 3.8. |
Those are the changes with the current behavior from the behavior in 3.5 observed at the time of the initial bug report: Applying the last patch fixes both 3.7 and 3.8. I can build a PR from this patch. An explanation should be given for the behavior of 3.7 and 3.8 in the jump.py case. |
Added PR 5928 for the 3.7 branch. |
Are there any problems with rebasing it to master? |
Yes, rebase fails merging two changes in Objects/frameobject.c. |
Usually we create a PR for master (unless the issue is gone here) and backport it to other branches. In this case it may be better to start from 3.7, but it is worth to look at the patch against master for the case if the change can written in the form that minimizes difference between 3.7 and master. |
Actually $ git rebase --onto master 3.7 bpo-17288 fails with one single change in Objects/frameobject.c and one simply needs to (as I have tested it) min_addr = Py_MIN(new_lasti, f->f_lasti);
max_addr = Py_MAX(new_lasti, f->f_lasti); then run: $ git add Objects/frameobject.c
$ git rebase --continue
$ git co master; git merge bpo-17288 |
xdegaye wrote:
In 3.7 when running jump.py as in msg183254, Python aborts with a frame stack overflow. The reason is that when the generator is resumed after the jump, its send() method is called with an argument and pushes the argument on the frame stack (i.e. f->f_stacktop - f->f_valuestack == 1 in gen_send_ex() before the call to PyEval_EvalFrameEx()). This argument is supposed to be popped by the first instruction executed by the generator which is expected to be YIELD_VALUE but, because of the jump, f->f_lasti is now 0 and the send() argument is not popped. Hence the stack overflow. When LLTRACE is undefined in ceval.c, stack oveflow checking is disabled. I have checked with gdb that, in that case, when YIELD_VALUE is about to be executed then STACK_LEVEL() is 3 instead of 1 and therefore YIELD_VALUE does not pop the right value from the stack. The stack is indeed corrupted. So there are two reasons for forbiddig to jump from a yield statement:
|
Thank you Xavier. I had pleasure from reviewing your patch. But please update tests for using the jump_test() decorator. |
Sorry, for some reason github did not send me the emails of your review and I did not think about checking the PR :-( |
Serhiy, I have updated the tests for using the jump_test() decorator and replied to your comment about RETURN_VALUE. |
In PR 5928 Serhiy Storchaka wrote:
Yes. |
Thank you! Do you mind to make a backport to 2.7 (if this makes a sense)? |
The conditions used for the fix are still the same in 2.7: f->f_trace == NULL on a call event, f->f_lasti == -1 in a new frame and f->f_stacktop == NULL in a trace function with a non-line event except for yield statements. Added a PR for 2.7. |
FWIW I now get github notifications, the problem was some bad configuration of my github profile (my fault). |
Thank you Xavier! |
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
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: