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
The last paragraph of Objects/lnotab_notes.txt explains that the f_lineno member of the PyFrameObject structure is needed to store the line number of the last "line" tracing event so that this value may be used as the line number of the "return" event instead of the (sometimes confusing) value computed from f_lasti. The f_lineno getter must then return the value of f->f_lineno (instead of the value computed from f->f_lasti) when tracing is set. The current implementation translates "tracing is set" as "the local f_trace trace function is not NULL", this is wrong for the following reasons:
AFAIK it is not documented anywhere that Python users implementing a trace function must delete the local f_trace functions of all the frames when setting the
global trace function to None via sys.settrace(None) (bpo-7238).
Bdb.set_continue() in the bdb module of the std lib seems to know about this and attempts to do it, but fails to delete f_trace from the topmost frame, named botframe (sic) (bpo-16482, bpo-17697).
It is not obvious how to delete the f_trace of all suspended generators when setting the global trace function to None (bpo-17277).
_PyTraceback_Add() in Python/traceback.c sets frame->f_lineno, obviously forgetting that it is useless since its f_trace is NULL.
This patch changes the semantics of f_lineno by stating that f_lineno is invalid when its value is -1. When tracing, the f_lineno of all the frames on the stack is valid. The f_lineno of a suspended generator is always invalid.
Could you please convert your patches to a PR Xavier?
xdegaye commented on Mar 22, 2018
xdegayemannequin
MannequinAuthor
More actions
I will work on it shortly.
xdegaye commented on Mar 25, 2018
xdegayemannequin
MannequinAuthor
More actions
A trace function may also be set in extension modules by PyEval_SetTrace() and it may not use f->f_trace. This is another reason why f->f_trace cannot be used in PyFrame_GetLineNumber() to know when f->f_lineno is valid.
xdegaye commented on Mar 25, 2018
xdegayemannequin
MannequinAuthor
More actions
Added PR 6233.
One of the GitHub bots failed to link this issue with PR 6233. Maybe this is related to the fact that connections to bpo are currently failing intermitently with the message:
An error occurred during a connection to bugs.python.org. Peer’s certificate has an invalid signature. Error code: SEC_ERROR_BAD_SIGNATURE
Fixed a bug in the implementation of PR 12419 while running the coverage.py test suite: f_lineno must be valid upon 'call' trace events. The confusion stems from the reason why until now we have prevented line jumps from 'call' trace events, see below.
Summary:
Full coverage.py tests OK (including the C tracer).
We could now remove the restriction that prevents jumps from a call trace event. The restriction was based on the fact that f->f_trace is NULL until after the first return from call_trampoline() and setting f_lineno from within this first call to call_trampoline() would have had the f_lineno getter still return the value returned by PyCode_Addr2Line(), very confusing for the user !
A trace function may be set in an extension modules by PyEval_SetTrace() and the extension module may not use f->f_trace and still make jumps using f_lineno.
% python3.8 -m pdb -c cont t-pdb.py
main...
Traceback (most recent call last):
File "…/pyenv/3.8.0/lib/python3.8/pdb.py", line 1702, in main
pdb._runscript(mainpyfile)
File "…/pyenv/3.8.0/lib/python3.8/pdb.py", line 1571, in _runscript
self.run(statement)
File "…/pyenv/3.8.0/lib/python3.8/bdb.py", line 587, in run
exec(cmd, globals, locals)
File "<string>", line 1, in <module>
File "…/Vcs/cpython/t-pdb.py", line 1, in <module>
import sys
File "…/Vcs/cpython/t-pdb.py", line 6, in main
assert 0
AssertionError
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> …/Vcs/cpython/t-pdb.py(6)main()
-> assert 0
(Pdb)
With the fix:
% /tmp/cpython-bisect/bin/python3.8 -m pdb -c cont t-pdb.py
main...
Traceback (most recent call last):
File "/tmp/cpython-bisect/lib/python3.8/pdb.py", line 1703, in main
pdb._runscript(mainpyfile)
File "/tmp/cpython-bisect/lib/python3.8/pdb.py", line 1572, in _runscript
self.run(statement)
File "/tmp/cpython-bisect/lib/python3.8/bdb.py", line 583, in run
exec(cmd, globals, locals)
File "<string>", line 1, in <module>
File "…/Vcs/cpython/t-pdb.py", line 10, in <module>
main()
File "…/Vcs/cpython/t-pdb.py", line 6, in main
assert 0
AssertionError
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> …/Vcs/cpython/t-pdb.py(6)main()
-> assert 0
(Pdb)
As you can see the traceback in the fixed case contains main() correctly,
while it has import sys (the scripts first line) otherwise.
I can only repeat myself to ask for reviewing/merging #12419.
It's been a while and the mechanisms were changed a lot in the past couple of versions. There's no usage of frame->f_trace in PyFrame_GetLineNumber anymore. The example given above also worked correctly for main. Close this for now, if someone found a repro, feel free to reopen this.
Activity
xdegaye commentedon Jul 4, 2015
The last paragraph of Objects/lnotab_notes.txt explains that the f_lineno member of the PyFrameObject structure is needed to store the line number of the last "line" tracing event so that this value may be used as the line number of the "return" event instead of the (sometimes confusing) value computed from f_lasti. The f_lineno getter must then return the value of f->f_lineno (instead of the value computed from f->f_lasti) when tracing is set. The current implementation translates "tracing is set" as "the local f_trace trace function is not NULL", this is wrong for the following reasons:
AFAIK it is not documented anywhere that Python users implementing a trace function must delete the local f_trace functions of all the frames when setting the
global trace function to None via sys.settrace(None) (bpo-7238).
Bdb.set_continue() in the bdb module of the std lib seems to know about this and attempts to do it, but fails to delete f_trace from the topmost frame, named botframe (sic) (bpo-16482, bpo-17697).
It is not obvious how to delete the f_trace of all suspended generators when setting the global trace function to None (bpo-17277).
_PyTraceback_Add() in Python/traceback.c sets frame->f_lineno, obviously forgetting that it is useless since its f_trace is NULL.
This patch changes the semantics of f_lineno by stating that f_lineno is invalid when its value is -1. When tracing, the f_lineno of all the frames on the stack is valid. The f_lineno of a suspended generator is always invalid.
xdegaye commentedon Jul 4, 2015
Uploading the corresponding test cases.
serhiy-storchaka commentedon Mar 22, 2018
Could you please convert your patches to a PR Xavier?
xdegaye commentedon Mar 22, 2018
I will work on it shortly.
xdegaye commentedon Mar 25, 2018
A trace function may also be set in extension modules by PyEval_SetTrace() and it may not use f->f_trace. This is another reason why f->f_trace cannot be used in PyFrame_GetLineNumber() to know when f->f_lineno is valid.
xdegaye commentedon Mar 25, 2018
Added PR 6233.
One of the GitHub bots failed to link this issue with PR 6233. Maybe this is related to the fact that connections to bpo are currently failing intermitently with the message:
An error occurred during a connection to bugs.python.org. Peer’s certificate has an invalid signature. Error code: SEC_ERROR_BAD_SIGNATURE
xdegaye commentedon Apr 8, 2019
Fixed a bug in the implementation of PR 12419 while running the coverage.py test suite: f_lineno must be valid upon 'call' trace events. The confusion stems from the reason why until now we have prevented line jumps from 'call' trace events, see below.
Summary:
cpython/Python/traceback.c
Line 272 in 58721a9
blueyed commentedon Dec 5, 2019
This is likely covered by existing/linked issues already, but wanted to leave it here nonetheless:
Given t-pdb.py:
Without the fix from the PR:
With the fix:
As you can see the traceback in the fixed case contains
main()correctly,while it has
import sys(the scripts first line) otherwise.I can only repeat myself to ask for reviewing/merging #12419.
gaogaotiantian commentedon May 3, 2024
It's been a while and the mechanisms were changed a lot in the past couple of versions. There's no usage of
frame->f_traceinPyFrame_GetLineNumberanymore. The example given above also worked correctly for main. Close this for now, if someone found a repro, feel free to reopen this.