ssl: store SSL socket owners as weak references (#8423)

Assisted-by: Codex:gpt-5.6-sol
This commit is contained in:
Jeaeun Kim authored and GitHub committed 2026-08-03 01:38:44 +09:00
1 parent 95f9d17dc2
commit 12f3646e7b
3 files changed
+31 -11

No files matched your search

-2
View File
@@ -738,7 +738,6 @@ class TestSSL(test_utils.TestCase):
asyncio.wait_for(client(srv.addr),
timeout=support.SHORT_TIMEOUT))
@unittest.expectedFailure # TODO: RUSTPYTHON; - gc.collect() doesn't release SSLContext properly
def test_create_connection_memory_leak(self):
HELLO_MSG = b'1' * self.PAYLOAD_SIZE
@@ -1617,7 +1616,6 @@ class TestSSL(test_utils.TestCase):
else:
self.fail('Unexpected ResourceWarning: {}'.format(cm.warning))
@unittest.expectedFailure # TODO: RUSTPYTHON; - gc.collect() doesn't release SSLContext properly
def test_handshake_timeout_handler_leak(self):
s = socket.socket(socket.AF_INET)
s.bind(('127.0.0.1', 0))
-1
View File
@@ -1479,7 +1479,6 @@ class ContextTests(unittest.TestCase):
ctx.set_servername_callback(None)
ctx.set_servername_callback(dummycallback)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Expected 'mock' to not have been called. Called 1 times.
def test_sni_callback_on_dead_references(self):
# See https://github.com/python/cpython/issues/146080.
c_ctx = make_test_context()
+31 -8
View File
@@ -48,7 +48,7 @@ mod _ssl {
VirtualMachine,
builtins::{
PyBaseExceptionRef, PyByteArray, PyBytesRef, PyListRef, PyStrRef, PyType,
PyTypeRef, PyUtf8StrRef,
PyTypeRef, PyUtf8StrRef, PyWeak,
},
convert::IntoPyException,
function::{
@@ -1920,7 +1920,12 @@ mod _ssl {
connection: PyMutex::new(None),
handshake_done: PyMutex::new(false),
session_was_reused: PyMutex::new(false),
owner: PyRwLock::new(args.owner.into_option()),
owner: PyRwLock::new(
args.owner
.into_option()
.map(|o| o.downgrade(None, vm))
.transpose()?,
),
// Filter out Python None objects - only store actual SSLSession objects
session: PyRwLock::new(args.session.into_option().filter(|s| !vm.is_none(s))),
incoming_bio: None,
@@ -1997,7 +2002,12 @@ mod _ssl {
connection: PyMutex::new(None),
handshake_done: PyMutex::new(false),
session_was_reused: PyMutex::new(false),
owner: PyRwLock::new(args.owner.into_option()),
owner: PyRwLock::new(
args.owner
.into_option()
.map(|o| o.downgrade(None, vm))
.transpose()?,
),
// Filter out Python None objects - only store actual SSLSession objects
session: PyRwLock::new(args.session.into_option().filter(|s| !vm.is_none(s))),
incoming_bio: Some(args.incoming),
@@ -2377,7 +2387,7 @@ mod _ssl {
#[pytraverse(skip)]
session_was_reused: PyMutex<bool>,
// Owner (SSLSocket instance that owns this _SSLSocket)
owner: PyRwLock<Option<PyObjectRef>>,
owner: PyRwLock<Option<PyRef<PyWeak>>>,
// Session for resumption
session: PyRwLock<Option<PyObjectRef>>,
// MemoryBIO mode (optional)
@@ -2734,7 +2744,19 @@ mod _ssl {
return Ok(());
};
let ssl_sock = self.owner.read().clone().unwrap_or_else(|| vm.ctx.none());
let ssl_sock = self
.owner
.read()
.as_ref()
.and_then(|owner| owner.upgrade())
.ok_or_else(|| {
super::compat::SslError::create_ssl_error_with_reason(
vm,
Some("SSL"),
"CALLBACK_FAILED",
"[SSL: CALLBACK_FAILED] callback failed",
)
})?;
let server_name_py: PyObjectRef = match sni_name {
Some(name) => vm.ctx.new_str(name.to_string()).into(),
None => vm.ctx.none(),
@@ -3955,12 +3977,13 @@ mod _ssl {
#[pygetset]
fn owner(&self) -> Option<PyObjectRef> {
self.owner.read().clone()
self.owner.read().as_ref().and_then(|owner| owner.upgrade())
}
#[pygetset(setter)]
fn set_owner(&self, owner: PyObjectRef, _vm: &VirtualMachine) {
*self.owner.write() = Some(owner);
fn set_owner(&self, owner: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
*self.owner.write() = Some(owner.downgrade(None, vm)?);
Ok(())
}
#[pygetset]