Skip to content
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

pdb cannot find source code for frozen stdlib modules #93696

Closed
SnoopJ opened this issue Jun 10, 2022 · 12 comments
Closed

pdb cannot find source code for frozen stdlib modules #93696

SnoopJ opened this issue Jun 10, 2022 · 12 comments
Labels
3.10 only security fixes 3.11 only security fixes 3.12 bugs and security fixes topic-importlib type-bug An unexpected behavior, bug, or error

Comments

@SnoopJ
Copy link
Contributor

SnoopJ commented Jun 10, 2022

Bug report

Context: this issue came out of a discussion in #python on the Libera.chat IRC network, where a user wanted to peek into importlib._bootstrap with pdb while chasing a bug.

pdb is capable of stepping into function calls into frozen modules, but the list command cannot locate the source code necessary to display the source being stepped through.

# repro.py
import importlib._bootstrap

# some function call that we want to step into with pdb
importlib._bootstrap._resolve_name("os", ".", 1)
$ python3 -m pdb repro.py
> /home/snoopjedi/repro.py(2)<module>()
-> import importlib._bootstrap
(Pdb) n
> /home/snoopjedi/repro.py(5)<module>()
-> importlib._bootstrap._resolve_name("os", ".", 1)
(Pdb) s
--Call--
> <frozen importlib._bootstrap>(883)_resolve_name()
(Pdb) l
[EOF]

Note that executing source importlib._bootstrap from the frame that calls into this module does successfully locate the source, but this isn't very useful to a user of pdb.

I believe that bringing the frame's co_filename into agreement with the module's __file__ would fix this issue without changes to pdb (see #89815), but thought it would be good to track the issue with pdb in a separate ticket since that fix is more nuanced and I think I have an interim patch for the debugger.

Your environment

  • CPython versions tested on: 3.9.4, 3.11.0b3
  • Operating system and architecture: Ubuntu 20.04, x86_64
@SnoopJ SnoopJ added the type-bug An unexpected behavior, bug, or error label Jun 10, 2022
SnoopJ added a commit to SnoopJ/cpython that referenced this issue Jun 12, 2022
@jacobtylerwalls
Copy link
Contributor

Likely duplicate of #60115

@SnoopJ
Copy link
Contributor Author

SnoopJ commented Jun 12, 2022

Likely duplicate of #60115

Definitely related inasmuch as importlib._bootstrap is involved, @exarkun is the user I mentioned in my report. Note that the issue does happen with other frozen modules, though, so the scope of the problem is expanding in 3.11 because of #89183. Here's an example showing the same problem with os.path

# repro2.py
import os.path

os.path.basename("/foo/bar/baz.py")  # implemented in Python

With Python 3.10:

$ python3.10 -m pdb repro2.py 
> /home/snoopjedi/repos/cpython/repro2.py(2)<module>()
-> import os.path
(Pdb) n
> /home/snoopjedi/repos/cpython/repro2.py(4)<module>()
-> os.path.basename("/foo/bar/baz.py")  # implemented in Python
(Pdb) s
--Call--
> /home/snoopjedi/.pyenv/versions/3.10.0/lib/python3.10/posixpath.py(140)basename()
-> def basename(p):
(Pdb) l
135         return p[:0], p
136  
137  
138     # Return the tail (basename) part of a path, same as split(path)[1].
139  
140  -> def basename(p):
141         """Returns the final component of a pathname"""
142         p = os.fspath(p)
143         sep = _get_sep(p)
144         i = p.rfind(sep) + 1
145         return p[i:]

With Python 3.11:

$ python3.11 -m pdb repro2.py 
> /home/snoopjedi/repos/cpython/repro2.py(2)<module>()
-> import os.path
(Pdb) n
> /home/snoopjedi/repos/cpython/repro2.py(4)<module>()
-> os.path.basename("/foo/bar/baz.py")  # implemented in Python
(Pdb) s
--Call--
> <frozen posixpath>(140)basename()
(Pdb) l
[EOF]
(Pdb)

@AA-Turner AA-Turner added 3.11 only security fixes 3.10 only security fixes topic-importlib 3.12 bugs and security fixes labels Jun 12, 2022
SnoopJ added a commit to SnoopJ/cpython that referenced this issue Jun 27, 2022
SnoopJ added a commit to SnoopJ/cpython that referenced this issue Jul 15, 2022
SnoopJ added a commit to SnoopJ/cpython that referenced this issue Jul 15, 2022
@SnoopJ
Copy link
Contributor Author

SnoopJ commented Jul 16, 2022

Pinging this issue per the devguide in the hopes of getting review on the PR, which has been open for a little while. I understand if things are too busy for review because of the release issues with 3.11, though!

SnoopJ added a commit to SnoopJ/cpython that referenced this issue Jul 17, 2022
@ericsnowcurrently
Copy link
Member

This should mostly be resolved in 3.10. See issue gh-65935 (and PR gh-28656). We now set __file__ for frozen stdlib modules. Could you give it a try?

@SnoopJ
Copy link
Contributor Author

SnoopJ commented Jul 21, 2022

This should mostly be resolved in 3.10. See issue gh-65935 (and PR gh-28656). We now set __file__ for frozen stdlib modules. Could you give it a try?

I get the same behavior as in the initial report against the current tip of 3.10 (b60c3d2):

13:29 [snoopjedi@denton ~/repos/cpython (3.10)]
$ ./python -c "import sys; print(sys.version)"
3.10.5+ (remotes/upstream/3.10:b60c3d2f7e, Jul 21 2022, 12:34:09) [GCC 9.4.0]
13:29 [snoopjedi@denton ~/repos/cpython (3.10)]
$ ./python -m pdb repro.py 
> /home/snoopjedi/repos/cpython/repro.py(2)<module>()
-> import importlib._bootstrap
(Pdb) n
> /home/snoopjedi/repos/cpython/repro.py(5)<module>()
-> importlib._bootstrap._resolve_name("os", ".", 1)
(Pdb) s
--Call--
> <frozen importlib._bootstrap>(902)_resolve_name()
(Pdb) l
[EOF]

The __file__ attribute is reported correctly (I believe this has been the case since before I filed this ticket, actually), but pdb is relying on co_filename and #89815 still applies

@ericsnowcurrently
Copy link
Member

Ah, thanks for checking. I missed that pdb wasn't using __file__. We should look at making sure co_filename is correct. I thought we were.

@SnoopJ
Copy link
Contributor Author

SnoopJ commented Jul 22, 2022

Yea, I'm not entirely sure what all goes into fixing the co_filename, but got the impression from your comment on that issue that it may be trickier than "just" patching the problem in pdb, hence this relatively unclever stopgap patch 😅

@ericsnowcurrently
Copy link
Member

Yeah, it may be worth adding the stopgap fix in the meantime.

@kumaraditya303
Copy link
Contributor

kumaraditya303 commented Aug 21, 2022

FYI I am looking into this. I'll probably make deepfreeze generate the correct co_filename but since this would have to be backported the stopgap solutions seems worth it. @ericsnowcurrently ?

SnoopJ added a commit to SnoopJ/cpython that referenced this issue Oct 24, 2022
JelleZijlstra pushed a commit that referenced this issue Oct 25, 2022
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 25, 2022
…3697)

Co-authored-by: Kumar Aditya <[email protected]>
(cherry picked from commit d91de28)

Co-authored-by: James Gerity <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 25, 2022
…3697)

Co-authored-by: Kumar Aditya <[email protected]>
(cherry picked from commit d91de28)

Co-authored-by: James Gerity <[email protected]>
miss-islington added a commit that referenced this issue Oct 25, 2022
Co-authored-by: Kumar Aditya <[email protected]>
(cherry picked from commit d91de28)

Co-authored-by: James Gerity <[email protected]>
miss-islington added a commit that referenced this issue Oct 25, 2022
Co-authored-by: Kumar Aditya <[email protected]>
(cherry picked from commit d91de28)

Co-authored-by: James Gerity <[email protected]>
@SnoopJ SnoopJ closed this as completed Oct 25, 2022
@rh314
Copy link

rh314 commented May 16, 2024

I'm adding this here in case anyone has to debug an older version of python and you still need pdb to step through "<frozen ...>".
Adapt it as needed according to the modules/files you need to debug.

This is an example of how to make the source lines available for <frozen importlib._bootstrap> on python3.9:
Early in your script(s), insert this:

import linecache

getline_original = linecache.getline
def getline_patched(filename, lineno, module_globals=None):
    if filename == '<frozen importlib._bootstrap>':
        filename = '/usr/lib/python3.9/importlib/_bootstrap.py'
    return getline_original(filename, lineno, module_globals)

linecache.getline = getline_patched

I also found this, but it didn't work for me; hence the code above.

@SnoopJ
Copy link
Contributor Author

SnoopJ commented May 16, 2024

That workaround looks reasonable to me. I would suggest that users could replace the hard-coded /usr/lib/python3.9/ part with sysconfig.get_path("stdlib") to be slightly more portable across installations and Python versions, but the truly portable fix that works for all frozen files is in the associated PR 😸

@rh314
Copy link

rh314 commented May 18, 2024

I completely agree with you @SnoopJ, the associated PR is indeed the permanent solution. 🏆

In my situation, I had to work on a legacy system, and recompiling/changing the filesystem was not an option available to me at the time. 🥲

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 only security fixes 3.11 only security fixes 3.12 bugs and security fixes topic-importlib type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

6 participants