Skip to content

Commit 969300d

Browse files
leak references for safety in PyWeakRefMethods::upgrade_borrowed (#4590)
* Add PyWeakref_GetRef and use it in weakref wrappers. (#4528) * deprecate weakref methods that return borrowed references --------- Co-authored-by: Nathan Goldbaum <[email protected]>
1 parent d01fbab commit 969300d

File tree

8 files changed

+215
-664
lines changed

8 files changed

+215
-664
lines changed

newsfragments/4528.added.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* Added bindings for `pyo3_ffi::PyWeakref_GetRef` on Python 3.13 and newer and
2+
`py03_ffi::compat::PyWeakref_GetRef` for older Python versions.

newsfragments/4590.changed.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Deprecate `_borrowed` methods on `PyWeakRef` and `PyWeakrefProxy` (just use the owning forms).

newsfragments/4590.fixed.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Workaround possible use-after-free in `_borrowed` methods on `PyWeakRef` and `PyWeakrefProxy` by leaking their contents.

pyo3-ffi/src/compat/py_3_13.rs

+33
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,36 @@ compat_function!(
3737
item
3838
}
3939
);
40+
41+
compat_function!(
42+
originally_defined_for(Py_3_13);
43+
44+
#[inline]
45+
pub unsafe fn PyWeakref_GetRef(
46+
reference: *mut crate::PyObject,
47+
pobj: *mut *mut crate::PyObject,
48+
) -> std::os::raw::c_int {
49+
use crate::{
50+
compat::Py_NewRef, PyErr_SetString, PyExc_TypeError, PyWeakref_Check,
51+
PyWeakref_GetObject, Py_None,
52+
};
53+
54+
if !reference.is_null() && PyWeakref_Check(reference) == 0 {
55+
*pobj = std::ptr::null_mut();
56+
PyErr_SetString(PyExc_TypeError, c_str!("expected a weakref").as_ptr());
57+
return -1;
58+
}
59+
let obj = PyWeakref_GetObject(reference);
60+
if obj.is_null() {
61+
// SystemError if reference is NULL
62+
*pobj = std::ptr::null_mut();
63+
return -1;
64+
}
65+
if obj == Py_None() {
66+
*pobj = std::ptr::null_mut();
67+
return 0;
68+
}
69+
*pobj = Py_NewRef(obj);
70+
1
71+
}
72+
);

pyo3-ffi/src/weakrefobject.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,12 @@ extern "C" {
5858
#[cfg_attr(PyPy, link_name = "PyPyWeakref_NewProxy")]
5959
pub fn PyWeakref_NewProxy(ob: *mut PyObject, callback: *mut PyObject) -> *mut PyObject;
6060
#[cfg_attr(PyPy, link_name = "PyPyWeakref_GetObject")]
61-
pub fn PyWeakref_GetObject(_ref: *mut PyObject) -> *mut PyObject;
61+
#[cfg_attr(
62+
Py_3_13,
63+
deprecated(note = "deprecated since Python 3.13. Use `PyWeakref_GetRef` instead.")
64+
)]
65+
pub fn PyWeakref_GetObject(reference: *mut PyObject) -> *mut PyObject;
66+
#[cfg(Py_3_13)]
67+
#[cfg_attr(PyPy, link_name = "PyPyWeakref_GetRef")]
68+
pub fn PyWeakref_GetRef(reference: *mut PyObject, pobj: *mut *mut PyObject) -> c_int;
6269
}

0 commit comments

Comments
 (0)