-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache #98591
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -344,20 +344,28 @@ def _flatten_literal_params(parameters): | |
|
||
|
||
_cleanups = [] | ||
_caches = {} | ||
|
||
|
||
def _tp_cache(func=None, /, *, typed=False): | ||
"""Internal wrapper caching __getitem__ of generic types with a fallback to | ||
original function for non-hashable arguments. | ||
""" | ||
def decorator(func): | ||
cached = functools.lru_cache(typed=typed)(func) | ||
_cleanups.append(cached.cache_clear) | ||
# The callback 'inner' references the newly created lru_cache | ||
# indirectly by performing a lookup in the global '_caches' dictionary. | ||
# This breaks a reference that can be problematic when combined with | ||
# C API extensions that leak references to types. See GH-98253. | ||
|
||
cache = functools.lru_cache(typed=typed)(func) | ||
_caches[func] = cache | ||
_cleanups.append(cache.cache_clear) | ||
del cache | ||
|
||
@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 commentThe 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 commentThe 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. |
||
except TypeError: | ||
pass # All real errors (not unhashable args) are raised below. | ||
return func(*args, **kwds) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
The implementation of the typing module is now more resilient to reference | ||
leaks in binary extension modules. | ||
|
||
Previously, a reference leak in a typed C API-based extension module could leak | ||
internals of the typing module, which could in turn introduce leaks in | ||
essentially any other package with typed function signatures. Although the | ||
typing package is not the original source of the problem, such non-local | ||
dependences exacerbate debugging of large-scale projects, and the | ||
implementation was therefore changed to reduce harm by providing better | ||
isolation. |
Uh oh!
There was an error while loading. Please reload this page.