Skip to content

Commit

Permalink
Update dict.get_item binding to use PyDict_GetItemRef
Browse files Browse the repository at this point in the history
Refs #4265
  • Loading branch information
ngoldbaum committed Jul 16, 2024
1 parent ee9123a commit b18581f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
2 changes: 2 additions & 0 deletions newsfragments/4355.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Avoid creating temporary borrowed reference in dict.get_item bindings. Borrowed
references like this are unsafe in the free-threading build.
26 changes: 26 additions & 0 deletions pyo3-ffi/src/dictobject.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::object::*;
#[cfg(not(Py_3_13))]
use crate::pyerrors::PyErr_Occurred;
use crate::pyport::Py_ssize_t;
use std::os::raw::{c_char, c_int};
use std::ptr::addr_of_mut;
Expand Down Expand Up @@ -58,6 +60,12 @@ extern "C" {
pub fn PyDict_MergeFromSeq2(d: *mut PyObject, seq2: *mut PyObject, _override: c_int) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyDict_GetItemString")]
pub fn PyDict_GetItemString(dp: *mut PyObject, key: *const c_char) -> *mut PyObject;
#[cfg(Py_3_13)]
pub fn PyDict_GetItemRef(
dp: *mut PyObject,
key: *mut PyObject,
result: *mut *mut PyObject,
) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyDict_SetItemString")]
pub fn PyDict_SetItemString(
dp: *mut PyObject,
Expand Down Expand Up @@ -96,6 +104,24 @@ pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> c_int {
(PyDictKeys_Check(op) != 0 || PyDictItems_Check(op) != 0) as c_int
}

#[cfg(not(Py_3_13))]
pub unsafe fn PyDict_GetItemRef(
dp: *mut PyObject,
key: *mut PyObject,
result: *mut *mut PyObject,
) -> c_int {
let item: *mut PyObject = PyDict_GetItemWithError(dp, key);
if !item.is_null() {
*result = _Py_NewRef(item);
return 1; // found
}
*result = std::ptr::null_mut();
if !PyErr_Occurred().is_null() {
return 0; // not found
}
-1
}

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
pub static mut PyDictIterKey_Type: PyTypeObject;
Expand Down
13 changes: 6 additions & 7 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,12 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
key: Bound<'_, PyAny>,
) -> PyResult<Option<Bound<'py, PyAny>>> {
let py = dict.py();
match unsafe {
ffi::PyDict_GetItemWithError(dict.as_ptr(), key.as_ptr())
.assume_borrowed_or_opt(py)
.map(Borrowed::to_owned)
} {
some @ Some(_) => Ok(some),
None => PyErr::take(py).map(Err).transpose(),
unsafe {
let mut result: *mut ffi::PyObject = std::ptr::null_mut();
match ffi::PyDict_GetItemRef(dict.as_ptr(), key.as_ptr(), &mut result) {
std::os::raw::c_int::MIN..=0 => PyErr::take(py).map(Err).transpose(),
1..=std::os::raw::c_int::MAX => Ok(result.assume_owned_or_opt(py)),
}
}
}

Expand Down

0 comments on commit b18581f

Please sign in to comment.