-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
gh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache #98591
Conversation
PS: It would be good to merge this not only in Python 3.12, but also older versions (3.11, 3.10, 3.9, 3.8). |
3.8 and 3.9 are now only accepting security-related patches, so this definitely won't be backported that far, I'm afraid. |
Fair enough. In that case, I propose to target 3.10, 3.11, and 3.12. |
As mentioned in the issue I'm skeptical that this is something we should fix in typing.py. I'll ask for input from other core devs (after the dust from the 3.11 release settles). |
I'm skeptical too. I feel that the tool is incorrectly blaming typing.py. |
@gvanrossum, did you see the discussion in #98253? When I first reported the issue, the actual source of these refleaks was mysterious. Further along the discussion thread, the problem was finally tracked down (see post #98253 (comment)) (Summary: refleaks in extension module tend to hold typed function signatures alive for eternity. This function signature references In this way, the caching mechanism in The patch in this PR is simple and it breaks this problematic chain of references. Of course, one could say: let's leave |
If by "the tool", you mean the nanobind-based reproducer, please let me know. It would be straightforward to reproduce the leak with a minimal CPython extension. I can sit down and make such a reproducer, but I would prefer to only do so if it's time well spent (in the sense that there is willingness to fix the issue if convincingly demonstrated). |
Speaking as a typing maintainer, Theoretically, I would like to say that the onus is on the external code to fix their refleaks. Since in this case as you have pointed out, typing.py doesn't have any refleaks. It just worsens external ones. However, I'm not opposed to the change (+0.5), because there aren't that many more lines of code. So the maintenance burden to support something like this isn't large. Also as you have rightly pointed out, it's nearly impossible to get all extension modules to fix all their refleaks. So I'm satisfied with typing not making them worse. |
@wjakob Never mind. I trust @Fidget-Spinner here. |
P.S I am not a typing maintainer so I'll defer to @Fidget-Spinner. |
There are a few misconceptions in the above message, I'll try to clarify.
While this PR does introduce a static state variable, it represents state that is already static (the caches). FWIW there is a
This is already what is happening. The leaks in question don't cause issues for those respective packages. The problem is that the internal mechanics of the typing module spread these leaks to other modules, which is where it becomes problematic. As mentioned in the associated issue, expecting all other extensions to be fixed is is going to be an impossible game of whack-a-mole. |
cpython/Lib/test/libregrtest/utils.py Lines 211 to 212 in de69816
|
There seems to be a miscommunication here. When Kumar wrote "static global state in extension modules is bad" he meant C code (maybe referring to the bug you found in some extension?). This has nothing to do with static state in a .py module like referenced by this PR. So let's please all calm down. |
Misc/NEWS.d/next/Library/2022-10-24-11-01-05.gh-issue-98253.HVd5v4.rst
Outdated
Show resolved
Hide resolved
@rhettinger : I added a longer paragraph summarizing the issue and incorporated your feedback. |
Please don't force-push to CPython PRs after review/discussion has started. It interacts badly with GitHub's UI, making it harder to see what exactly changed since we last looked at the PR :) |
Sorry 😇. For posterity, I amended the commit to replace the contents of the file |
|
||
@functools.wraps(func) | ||
def inner(*args, **kwds): | ||
try: | ||
return cached(*args, **kwds) | ||
return _caches[func](*args, **kwds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be marginally slower because instead of a single cell variable lookup, we do a global lookup, a cell variable, and a subscript. Probably not enough to matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming we don't backport this: this should still be potentially faster in 3.12 than in 3.11.
Dear all, It seems to me that the decision process regarding this PR has stalled. It would be good to come to a decision on how to proceed (accept, reject, further changes requested, ...?) Thanks in advance! |
I will accept it as an enhancement to typing soon (ie it wont be backported). Sorry for the wait, I was busy with uni exams. |
@serhiy-storchaka or @JelleZijlstra does the code look okay to y'all? I plan to merge this soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with this to go in, but I think a short comment wouldn't go amiss :) there's already a lot of code in typing.py
that's quite subtle
It's quite puzzling -- I pushed two further commits to address your feedback, but they don't show up here. Perhaps a GitHub service issue/outage? See main...wjakob:cpython:typing-leak |
GitHub is quite laggy right now in general, I'm seeing it on |
Yes, GitHub is apparently having some issues; I saw it on other PRs. I did get emails for the two commits you pushed. |
Edit: now, something is happening. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy for this to be merged (but will wait for at least one other approval before merging)
https://www.githubstatus.com/ reports some degradation. |
* main: (112 commits) pythongh-99894: Ensure the local names don't collide with the test file in traceback suggestion error checking (python#99895) pythongh-99612: Fix PyUnicode_DecodeUTF8Stateful() for ASCII-only data (pythonGH-99613) Doc: Add summary line to isolation_level & autocommit sqlite3.connect params (python#99917) pythonGH-98906 ```re``` module: ```search() vs. match()``` section should mention ```fullmatch()``` (pythonGH-98916) pythongh-89189: More compact range iterator (pythonGH-27986) bpo-47220: Document the optional callback parameter of weakref.WeakMethod (pythonGH-25491) pythonGH-99905: Fix output of misses in summarize_stats.py execution counts (pythonGH-99906) pythongh-99845: PEP 670: Convert PyObject macros to functions (python#99850) pythongh-99845: Use size_t type in __sizeof__() methods (python#99846) pythonGH-99877) Fix typo in exception message in `multiprocessing.pool` (python#99900) pythongh-87092: move all localsplus preparation into separate function called from assembler stage (pythonGH-99869) pythongh-99891: Fix infinite recursion in the tokenizer when showing warnings (pythonGH-99893) pythongh-99824: Document that sqlite3.connect implicitly open a transaction if autocommit=False (python#99825) pythonGH-81057: remove static state from suggestions.c (python#99411) Improve zip64 limit error message (python#95892) pythongh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache (python#98591) pythongh-99127: Allow some features of syslog to the main interpreter only (pythongh-99128) pythongh-82836: fix private network check (python#97733) Docs: improve accuracy of socketserver reference (python#24767) ...
The
typing
module internally uses LRU caches to memoize the result of type-related computations. These LRU caches have the potential to introduce difficult-to-find reference leaks spanning multiple extension modules.Suppose that a binary extension module
a
leaks a reference to a typea.A
with typed function signatures.The leaked type
a.A
will induce a secondary refleak of thetyping
LRU caches, which will at this point cause tertiary leaks in entirely unrelated extension modules. In this way, a benign refleak in any extension can cause difficult-to-debug leaks everywhere else.This commit fixes this by removing the direct reference from
a.A
totyping
implementation details.