Skip to content

Commit f7e845d

Browse files
committed
ssl: store SSL socket owners as weak references
Assisted-by: Codex:gpt-5.6-sol
1 parent f08933b commit f7e845d

2 files changed

Lines changed: 31 additions & 9 deletions

File tree

Lib/test/test_ssl.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,6 @@ def dummycallback(sock, servername, ctx):
14821482
ctx.set_servername_callback(None)
14831483
ctx.set_servername_callback(dummycallback)
14841484

1485-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Expected 'mock' to not have been called. Called 1 times.
14861485
def test_sni_callback_on_dead_references(self):
14871486
# See https://github.com/python/cpython/issues/146080.
14881487
c_ctx = make_test_context()

crates/stdlib/src/ssl.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ mod _ssl {
4848
VirtualMachine,
4949
builtins::{
5050
PyBaseExceptionRef, PyByteArray, PyBytesRef, PyListRef, PyStrRef, PyType,
51-
PyTypeRef, PyUtf8StrRef,
51+
PyTypeRef, PyUtf8StrRef, PyWeak,
5252
},
5353
convert::IntoPyException,
5454
function::{
@@ -1898,7 +1898,12 @@ mod _ssl {
18981898
connection: PyMutex::new(None),
18991899
handshake_done: PyMutex::new(false),
19001900
session_was_reused: PyMutex::new(false),
1901-
owner: PyRwLock::new(args.owner.into_option()),
1901+
owner: PyRwLock::new(
1902+
args.owner
1903+
.into_option()
1904+
.map(|o| o.downgrade(None, vm))
1905+
.transpose()?,
1906+
),
19021907
// Filter out Python None objects - only store actual SSLSession objects
19031908
session: PyRwLock::new(args.session.into_option().filter(|s| !vm.is_none(s))),
19041909
incoming_bio: None,
@@ -1975,7 +1980,12 @@ mod _ssl {
19751980
connection: PyMutex::new(None),
19761981
handshake_done: PyMutex::new(false),
19771982
session_was_reused: PyMutex::new(false),
1978-
owner: PyRwLock::new(args.owner.into_option()),
1983+
owner: PyRwLock::new(
1984+
args.owner
1985+
.into_option()
1986+
.map(|o| o.downgrade(None, vm))
1987+
.transpose()?,
1988+
),
19791989
// Filter out Python None objects - only store actual SSLSession objects
19801990
session: PyRwLock::new(args.session.into_option().filter(|s| !vm.is_none(s))),
19811991
incoming_bio: Some(args.incoming),
@@ -2349,7 +2359,7 @@ mod _ssl {
23492359
#[pytraverse(skip)]
23502360
session_was_reused: PyMutex<bool>,
23512361
// Owner (SSLSocket instance that owns this _SSLSocket)
2352-
owner: PyRwLock<Option<PyObjectRef>>,
2362+
owner: PyRwLock<Option<PyRef<PyWeak>>>,
23532363
// Session for resumption
23542364
session: PyRwLock<Option<PyObjectRef>>,
23552365
// MemoryBIO mode (optional)
@@ -2706,7 +2716,19 @@ mod _ssl {
27062716
return Ok(());
27072717
};
27082718

2709-
let ssl_sock = self.owner.read().clone().unwrap_or_else(|| vm.ctx.none());
2719+
let ssl_sock = self
2720+
.owner
2721+
.read()
2722+
.as_ref()
2723+
.and_then(|owner| owner.upgrade())
2724+
.ok_or_else(|| {
2725+
super::compat::SslError::create_ssl_error_with_reason(
2726+
vm,
2727+
Some("SSL"),
2728+
"CALLBACK_FAILED",
2729+
"[SSL: CALLBACK_FAILED] callback failed",
2730+
)
2731+
})?;
27102732
let server_name_py: PyObjectRef = match sni_name {
27112733
Some(name) => vm.ctx.new_str(name.to_string()).into(),
27122734
None => vm.ctx.none(),
@@ -3927,12 +3949,13 @@ mod _ssl {
39273949

39283950
#[pygetset]
39293951
fn owner(&self) -> Option<PyObjectRef> {
3930-
self.owner.read().clone()
3952+
self.owner.read().as_ref().and_then(|owner| owner.upgrade())
39313953
}
39323954

39333955
#[pygetset(setter)]
3934-
fn set_owner(&self, owner: PyObjectRef, _vm: &VirtualMachine) {
3935-
*self.owner.write() = Some(owner);
3956+
fn set_owner(&self, owner: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
3957+
*self.owner.write() = Some(owner.downgrade(None, vm)?);
3958+
Ok(())
39363959
}
39373960

39383961
#[pygetset]

0 commit comments

Comments
 (0)