-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
_socket extension C capsule cannot be visited by the GC and so _socket.socket type may stay alive longer than expected #108240
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
Comments
_socket.CAPI capsule contains a strong reference to _socket.socket type. The garbage collector cannot visit this reference and so cannot create the reference cycle involving _socket.socket (a heap type creates a reference cycle to inside, via MRO and methods). At Python, _PyImport_ClearModules() sets _socket attributes to None which works around the issue. If the module is cleared from sys.modules manually, _PyImport_ClearModules() cannot set _socket.CAPI to None and so the issue cannot be worked around. Change _socket.CAPI to use a borrowed reference instead of a strong reference to allow clearing _socket.socket in this case. Co-authored-by: Kirill Podoprigora <[email protected]>
I wrote PR #108241 to fix the issue for the _socket extension: avoid strong references in the capsule object. |
Extensions not affected by the issue, using borrowed references:
|
I closed issue #107789 as a duplicate of this issue. |
Oh, @Eclips4 found that the |
Probably related: #107994 |
Oh right, the |
cc @erlend-aasland @corona10 @pablogsal: yet another complex GC issue involving extension multi-phase initialization and the garbage collector. |
The |
You mean leak in the import importlib
import sys
def foo():
name = "_curses"
importlib.import_module(name)
del sys.modules[name]
for _ in range(4):
foo()
./python.exe -X showrefcount example.py
[1006 refs, 491 blocks] |
Yes. It should be ported to multi-phase init and its static types should be converted to heap types. |
FYI, it seems that work on isolating the |
So, should we re-open @chgnrdv PR about isolating |
Using |
The issue with _curses is that it leaks references, and so it makes debugging real leaks more complicated at Python exit:
I fixed some stdlib extensions by adding _PyTypes_FiniTypes() function which is called at Python exit. The problem here is that the _curses extension is a shared library, so Python cannot track its types. Maybe an "at exit" callback can be used for such cases (but not Py_AtExit() which calls the callback after the interpreter is deleted). Converting _curses to multi-phase init would give more freedom on how resources are released. |
The problem with curses and readline is that they rely on process wide globals, which mean module state just won't do it. Try converting readline to multi-phase init, and you'll see what I mean :) Tkinter has similar issues. |
The |
Yes, storing the state in the interpreter is an option, but I don't think we want to do that for tkinter, readline, and curses. |
The _socket extension uses PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses _PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses _PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
The _socket extension uses _PyCapsule_SetTraverse() to visit and clear the socket type in the garbage collector. So the _socket.socket type can be cleared in some corner cases when it wasn't possible before.
Move _PyCapsule_SetTraverse() definition to a new internal header file: pycore_capsule.h.
Move _PyCapsule_SetTraverse() definition to a new internal header file: pycore_capsule.h.
Bug report
Checklist
and am confident this bug has not been reported before
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.13.0a0 (heads/main:d63972e289, Aug 21 2023, 22:29:24) [GCC 13.2.1 20230728 (Red Hat 13.2.1-1)]
A clear and concise description of the bug:
The following script will never delete
_socket.socket
type:Example on a Python debug build:
$ ./python -X showrefcount script.py exit [408 refs, 260 blocks]
The GC cannot visit the strong reference to the type stored in
_socket.CAPI
capsule (C API). In Python, creating a heap type creates a reference cycle. For example, a type MRO contains the type. Methods also contain a strong reference to their type.See also:
Linked PRs
The text was updated successfully, but these errors were encountered: