Skip to content

Commit

Permalink
leak references for safety in PyWeakRefMethods::upgrade_borrowed (#…
Browse files Browse the repository at this point in the history
…4590)

* Add PyWeakref_GetRef and use it in weakref wrappers. (#4528)

* deprecate weakref methods that return borrowed references

---------

Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
  • Loading branch information
davidhewitt and ngoldbaum committed Oct 12, 2024
1 parent d01fbab commit 969300d
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 664 deletions.
2 changes: 2 additions & 0 deletions newsfragments/4528.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Added bindings for `pyo3_ffi::PyWeakref_GetRef` on Python 3.13 and newer and
`py03_ffi::compat::PyWeakref_GetRef` for older Python versions.
1 change: 1 addition & 0 deletions newsfragments/4590.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Deprecate `_borrowed` methods on `PyWeakRef` and `PyWeakrefProxy` (just use the owning forms).
1 change: 1 addition & 0 deletions newsfragments/4590.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Workaround possible use-after-free in `_borrowed` methods on `PyWeakRef` and `PyWeakrefProxy` by leaking their contents.
33 changes: 33 additions & 0 deletions pyo3-ffi/src/compat/py_3_13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,36 @@ compat_function!(
item
}
);

compat_function!(
originally_defined_for(Py_3_13);

#[inline]
pub unsafe fn PyWeakref_GetRef(
reference: *mut crate::PyObject,
pobj: *mut *mut crate::PyObject,
) -> std::os::raw::c_int {
use crate::{
compat::Py_NewRef, PyErr_SetString, PyExc_TypeError, PyWeakref_Check,
PyWeakref_GetObject, Py_None,
};

if !reference.is_null() && PyWeakref_Check(reference) == 0 {
*pobj = std::ptr::null_mut();
PyErr_SetString(PyExc_TypeError, c_str!("expected a weakref").as_ptr());
return -1;
}
let obj = PyWeakref_GetObject(reference);
if obj.is_null() {
// SystemError if reference is NULL
*pobj = std::ptr::null_mut();
return -1;
}
if obj == Py_None() {
*pobj = std::ptr::null_mut();
return 0;
}
*pobj = Py_NewRef(obj);
1
}
);
9 changes: 8 additions & 1 deletion pyo3-ffi/src/weakrefobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,12 @@ extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyWeakref_NewProxy")]
pub fn PyWeakref_NewProxy(ob: *mut PyObject, callback: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyWeakref_GetObject")]
pub fn PyWeakref_GetObject(_ref: *mut PyObject) -> *mut PyObject;
#[cfg_attr(
Py_3_13,
deprecated(note = "deprecated since Python 3.13. Use `PyWeakref_GetRef` instead.")
)]
pub fn PyWeakref_GetObject(reference: *mut PyObject) -> *mut PyObject;
#[cfg(Py_3_13)]
#[cfg_attr(PyPy, link_name = "PyPyWeakref_GetRef")]
pub fn PyWeakref_GetRef(reference: *mut PyObject, pobj: *mut *mut PyObject) -> c_int;
}
Loading

0 comments on commit 969300d

Please sign in to comment.