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

gh-108240: Add _PyCapsule_SetTraverse() internal function #108339

Merged
merged 1 commit into from
Aug 23, 2023

Conversation

vstinner
Copy link
Member

@vstinner vstinner commented Aug 22, 2023

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.


📚 Documentation preview 📚: https://cpython-previews--108339.org.readthedocs.build/

@vstinner
Copy link
Member Author

@erlend-aasland: Here is a more complete solution to add traverse/clear functions to the socket C API capsule.

@Eclips4
Copy link
Member

Eclips4 commented Aug 22, 2023

IMO, I like this solution more than #108241, because #108241 looks like a solution of corner case.

Copy link
Member Author

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this function should not be added to the limited C API.

@vstinner
Copy link
Member Author

test_ssl fails on macOS and altered the environment when re-run in verbose mode:

ERROR: test_preauth_data_to_tls_client (test.test_ssl.TestPreHandshakeClose.test_preauth_data_to_tls_client)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/runner/work/cpython/cpython/Lib/test/test_ssl.py", line 4802, in test_preauth_data_to_tls_client
    client.connect(server.listener.getsockname())
ConnectionResetError: [Errno 54] Connection reset by peer
(...)
Warning -- threading_cleanup() failed to cleanup 0 threads (count: 0, dangling: 2)
Warning -- Dangling thread: <SingleConnectionTestServerThread(preauth_data_to_tls_client, stopped 123145440923648)>
Warning -- Dangling thread: <_MainThread(MainThread, started 4610459136)>

test.pythoninfo:

ssl.OPENSSL_VERSION: OpenSSL 3.0.10 1 Aug 2023
ssl.OPENSSL_VERSION_INFO: (3, 0, 0, 10, 0)

@erlend-aasland
Copy link
Contributor

@erlend-aasland: Here is a more complete solution to add traverse/clear functions to the socket C API capsule.

As I mentioned to you earlier, I had thoughts of a similar API, and I think this is a better solution to the problem than #108241. I think we should get more eyes on the API, though. If we are to make it public right away, we should be sure to get it right the first time ;) Perhaps create a topic on Discourse?

@vstinner
Copy link
Member Author

I removed the new function from the limited C API.

@vstinner vstinner changed the title gh-108240: Add PyCapsule_SetTraverse() function gh-108240: Add _PyCapsule_SetTraverse() internal function Aug 23, 2023
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.
@vstinner
Copy link
Member Author

Since this function is only used for a single extension yet, the _socket extension, I changed my PR to only add the function to the internal C API (Py_BUILD_CORE). This function can be made public later if needed.

@vstinner vstinner merged commit 513c89d into python:main Aug 23, 2023
@vstinner vstinner deleted the capsule_traverse branch August 23, 2023 22:19
@vstinner
Copy link
Member Author

@Eclips4 @erlend-aasland: I chose the middle ground, start by making the API internal.

I tested manually that the change fix issue #108240 leak.

It's not worth it to backport the change it's a corner case to manually unload a module from sys.modules.

Comment on lines +207 to +208
if (!PyObject_GC_IsTracked(op)) {
PyObject_GC_Track(op);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could have used the internal APIs here:

Suggested change
if (!PyObject_GC_IsTracked(op)) {
PyObject_GC_Track(op);
assert(_PyObject_IS_GC(op));
if (!_PyObject_GC_IS_TRACKED(op)) {
_PyObject_GC_TRACK(op);
}

OTOH, _PyCapsule_SetTraverse is probably not part of hot code, so I guess the public APIs are fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used _PyObject_GC_IS_TRACKED() in my second PR, but without assert(_PyObject_IS_GC(op)) which looks overkill.

Comment on lines +312 to +314
else {
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else is unneeded here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the callback can be NULL. I added a check in my second PR to reject NULL callbacks.

@erlend-aasland
Copy link
Contributor

@Eclips4 @erlend-aasland: I chose the middle ground, start by making the API internal.

I agree that keeping it internal makes sense for now. I do think a public API like this is needed, though.

It's not worth it to backport the change it's a corner case to manually unload a module from sys.modules.

I agree that we should not backport this PR.

@vstinner
Copy link
Member Author

@erlend-aasland: I wrote PR #108417 to address your review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants