diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index 932b1dace..ca15fc3bd 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -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)) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 107aec7e6..8dad1ba73 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -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() diff --git a/crates/stdlib/src/ssl.rs b/crates/stdlib/src/ssl.rs index 7c4257877..454fdcba8 100644 --- a/crates/stdlib/src/ssl.rs +++ b/crates/stdlib/src/ssl.rs @@ -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, // Owner (SSLSocket instance that owns this _SSLSocket) - owner: PyRwLock>, + owner: PyRwLock>>, // Session for resumption session: PyRwLock>, // 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 { - 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]