GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache by wjakob · Pull Request #98591 · python/cpython

Conversation

@wjakob

@wjakob wjakob commented Oct 24, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

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 type a.A with typed function signatures.

The leaked type a.A will induce a secondary refleak of the typing 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 to typing implementation details.

  • Issue: typing.py: builtin LRU caches worsen leaks that exist in other code #98253

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@wjakob
wjakob requested review from AlexWaygood, Fidget-Spinner, JelleZijlstra and gvanrossum as code owners October 24, 2022 09:02
@bedevere-bot bedevere-bot added the awaiting review label Oct 24, 2022
@wjakob

wjakob commented Oct 24, 2022

Copy link
Copy Markdown
Contributor Author

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).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob
wjakob force-pushed the typing-leak branch from 0ac2917 to 7291ac0 Compare October 24, 2022 09:28
@AlexWaygood

AlexWaygood commented Oct 24, 2022

Copy link
Copy Markdown
Member

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Oct 24, 2022

Copy link
Copy Markdown
Contributor Author

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JelleZijlstra

JelleZijlstra commented Oct 24, 2022

Copy link
Copy Markdown
Member

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).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Oct 24, 2022

Copy link
Copy Markdown
Member

I'm skeptical too. I feel that the tool is incorrectly blaming typing.py.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Oct 24, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

@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 typing.py internals (LRU caches), which in turn cast a web of references to other parts of the interpreter)

In this way, the caching mechanism in typing.py can turn virtually any refleak in any typed extension module into refleaks elsewhere. Ultimately, it becomes difficult to develop leak-free extensions, because any systematic checking for leaks runs into flukes. I'm creating a framework for extension modules that tries to be well-behaved in this ecosystem, but its internal tests for leaks are hampered by this behavior. Quick tests show that many of the bigger packages (pandas, pytorch, tensorflow) include some refleaks that are problematic in this context.

The patch in this PR is simple and it breaks this problematic chain of references. Of course, one could say: let's leave typing.py as-is and fix all of the other extension modules. I just don't think it is very practical to do so.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Oct 24, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

I'm skeptical too. I feel that the tool is incorrectly blaming typing.py.

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).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner Fidget-Spinner changed the title gh-98253: fix refleak issue in typing.py gh-98253: Break potential reference cycles in external code caused by typing.py lru_cache Oct 25, 2022
@Fidget-Spinner

Fidget-Spinner commented Oct 25, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

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.

gvanrossum reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Oct 25, 2022

Copy link
Copy Markdown
Member

@wjakob Never mind. I trust @Fidget-Spinner here.

Fidget-Spinner reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner Fidget-Spinner changed the title gh-98253: Break potential reference cycles in external code caused by typing.py lru_cache gh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache Oct 26, 2022
@kumaraditya303

kumaraditya303 commented Oct 26, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

static global state in extension modules is bad and should be avoided as much. See https://peps.python.org/pep-0489/
They are bad for multiple reasons not to mention they are a problem for sub-interpreter. I worry if we add workarounds for this in stdlib then library authors will never fix their own code and we will get more requests to add workarounds so that they don't have to fix their own code. Note that just clearing reference isn't enough here, when the GC is involved this can lead to very strange bugs and are a pain to debug. See a similar asyncio bug #96232 involving static c globals. For this specific case, this seems fine but we need to be cautious because if we add this then the extension authors will never notice that there is a bug in their code as it will probably "just work".

P.S I am not a typing maintainer so I'll defer to @Fidget-Spinner.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Oct 26, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There are a few misconceptions in the above message, I'll try to clarify.

static global state in extension modules is bad and should be avoided as much. [..] I worry if we add workarounds for this in stdlib then library authors will never fix their own code and we will get more requests to add workarounds so that they don't have to fix their own code.

While this PR does introduce a static state variable, it represents state that is already static (the caches). FWIW there is a _cleanup variable just a few lines above that serves the exact same purpose, so it does not seem like new ground is being broken.

[..] if we add this then the extension authors will never notice that there is a bug in their code as it will probably "just work".

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kumaraditya303

kumaraditya303 commented Oct 26, 2022

Copy link
Copy Markdown
Contributor

While this PR does introduce a static state variable, it represents state that is already static (the caches). FWIW there is a _cleanup variable just a few lines above that serves the exact same purpose, so it does not seem like new ground is being broken.

_cleanups has a different purpose, it is used by our test runner to check for reference leaks by clearing caches and it not used outside of that purpose.

cpython/Lib/test/libregrtest/utils.py

Lines 211 to 212 in de69816

for f in typing._cleanups:
f()

Fidget-Spinner and AlexWaygood reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Oct 26, 2022

Copy link
Copy Markdown
Member

While this PR does introduce a static state variable

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.

AlexWaygood, kumaraditya303, Fidget-Spinner, wjakob, and rhettinger reacted with thumbs up emoji wjakob reacted with heart emoji
All reactions
  • 👍 5 reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

rhettinger
rhettinger reviewed Oct 29, 2022
View reviewed changes
Comment thread Misc/NEWS.d/next/Library/2022-10-24-11-01-05.gh-issue-98253.HVd5v4.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner Fidget-Spinner added the type-feature A feature request or enhancement label Oct 29, 2022
@wjakob
wjakob force-pushed the typing-leak branch from 7291ac0 to 1ce6651 Compare October 31, 2022 19:56
@bedevere-bot bedevere-bot mentioned this pull request Oct 31, 2022
typing.py: builtin LRU caches worsen leaks that exist in other code #98253
Closed
@wjakob

wjakob commented Oct 31, 2022

Copy link
Copy Markdown
Contributor Author

@rhettinger : I added a longer paragraph summarizing the issue and incorporated your feedback.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob
break potential reference cycles in external code worsened by typing.…
2fed985
…py lru_cache (python#98253)
@wjakob
wjakob force-pushed the typing-leak branch from 1ce6651 to 2fed985 Compare October 31, 2022 19:58
@AlexWaygood

AlexWaygood commented Oct 31, 2022

Copy link
Copy Markdown
Member

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 :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Oct 31, 2022

Copy link
Copy Markdown
Contributor Author

Sorry 😇. For posterity, I amended the commit to replace the contents of the file Misc/NEWS.d/next/Library/2022-10-24-11-01-05.gh-issue-98253.HVd5v4.rst.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

JelleZijlstra
JelleZijlstra reviewed Oct 31, 2022
View reviewed changes
Comment thread Lib/typing.py
def inner(*args, **kwds):
try:
return cached(*args, **kwds)
return _caches[func](*args, **kwds)

@JelleZijlstra JelleZijlstra Oct 31, 2022

Copy link
Copy Markdown
Member

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@Fidget-Spinner Fidget-Spinner Nov 1, 2022

Copy link
Copy Markdown
Member

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@AlexWaygood AlexWaygood added the topic-typing label Nov 13, 2022
@wjakob

wjakob commented Nov 23, 2022

Copy link
Copy Markdown
Contributor Author

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!
Wenzel

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner

Fidget-Spinner commented Nov 24, 2022

Copy link
Copy Markdown
Member

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner

Fidget-Spinner commented Nov 24, 2022

Copy link
Copy Markdown
Member

@serhiy-storchaka or @JelleZijlstra does the code look okay to y'all? I plan to merge this soon.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

AlexWaygood
AlexWaygood reviewed Nov 24, 2022
View reviewed changes

@AlexWaygood AlexWaygood left a comment

Copy link
Copy Markdown
Member

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/typing.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/typing.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

wjakob added 2 commits November 25, 2022 16:01
@wjakob
added a comment clarifying the indirection
411fd55
@wjakob
removed superfluous space
f27e49d
@wjakob

wjakob commented Nov 25, 2022

Copy link
Copy Markdown
Contributor Author

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

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexWaygood

AlexWaygood commented Nov 25, 2022

Copy link
Copy Markdown
Member

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 typeshed and typing_extensions as well :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JelleZijlstra

JelleZijlstra commented Nov 25, 2022

Copy link
Copy Markdown
Member

Yes, GitHub is apparently having some issues; I saw it on other PRs. I did get emails for the two commits you pushed.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wjakob

wjakob commented Nov 25, 2022

Copy link
Copy Markdown
Contributor Author

Edit: now, something is happening.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

AlexWaygood
AlexWaygood approved these changes Nov 25, 2022
View reviewed changes

@AlexWaygood AlexWaygood left a comment

Copy link
Copy Markdown
Member

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)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-bot bedevere-bot added awaiting merge and removed awaiting review labels Nov 25, 2022
@JelleZijlstra

JelleZijlstra commented Nov 25, 2022

Copy link
Copy Markdown
Member

https://www.githubstatus.com/ reports some degradation.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Fidget-Spinner
Fidget-Spinner approved these changes Nov 30, 2022
View reviewed changes
@AlexWaygood
AlexWaygood merged commit c314198 into python:main Nov 30, 2022
@bedevere-bot bedevere-bot removed the awaiting merge label Nov 30, 2022
carljm added a commit to carljm/cpython that referenced this pull request Dec 1, 2022
@carljm
Merge branch 'main' into fixinspect
12f7659
* 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)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@JelleZijlstra JelleZijlstra JelleZijlstra left review comments
@rhettinger rhettinger rhettinger left review comments
@Fidget-Spinner Fidget-Spinner Fidget-Spinner approved these changes
@AlexWaygood AlexWaygood AlexWaygood approved these changes
@gvanrossum gvanrossum Awaiting requested review from gvanrossum

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

topic-typing type-feature A feature request or enhancement

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

8 participants

@wjakob @AlexWaygood @JelleZijlstra @gvanrossum @Fidget-Spinner @kumaraditya303 @rhettinger @bedevere-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.