Skip to content

Commit 9fae0be

Browse files
committed
Update dict.get_item binding to use PyDict_GetItemRef
Refs PyO3#4265
1 parent e0bd22e commit 9fae0be

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

newsfragments/4355.fixed.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid creating temporary borrowed reference in dict.get_item bindings. Borrowed
2+
references like this are unsafe in the free-threading build.

pyo3-ffi/src/dictobject.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::object::*;
2+
#[cfg(not(Py_3_13))]
3+
use crate::pyerrors::PyErr_Occurred;
24
use crate::pyport::Py_ssize_t;
35
use std::os::raw::{c_char, c_int};
46
use std::ptr::addr_of_mut;
@@ -58,6 +60,12 @@ extern "C" {
5860
pub fn PyDict_MergeFromSeq2(d: *mut PyObject, seq2: *mut PyObject, _override: c_int) -> c_int;
5961
#[cfg_attr(PyPy, link_name = "PyPyDict_GetItemString")]
6062
pub fn PyDict_GetItemString(dp: *mut PyObject, key: *const c_char) -> *mut PyObject;
63+
#[cfg(Py_3_13)]
64+
pub fn PyDict_GetItemRef(
65+
dp: *mut PyObject,
66+
key: *mut PyObject,
67+
result: *mut *mut PyObject,
68+
) -> c_int;
6169
#[cfg_attr(PyPy, link_name = "PyPyDict_SetItemString")]
6270
pub fn PyDict_SetItemString(
6371
dp: *mut PyObject,
@@ -96,6 +104,24 @@ pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> c_int {
96104
(PyDictKeys_Check(op) != 0 || PyDictItems_Check(op) != 0) as c_int
97105
}
98106

107+
#[cfg(not(Py_3_13))]
108+
pub unsafe fn PyDict_GetItemRef(
109+
dp: *mut PyObject,
110+
key: *mut PyObject,
111+
result: *mut *mut PyObject,
112+
) -> c_int {
113+
let item: *mut PyObject = PyDict_GetItemWithError(dp, key);
114+
if !item.is_null() {
115+
*result = _Py_NewRef(item);
116+
return 1; // found
117+
}
118+
*result = std::ptr::null_mut();
119+
if !PyErr_Occurred().is_null() {
120+
return 0; // not found
121+
}
122+
-1
123+
}
124+
99125
#[cfg_attr(windows, link(name = "pythonXY"))]
100126
extern "C" {
101127
pub static mut PyDictIterKey_Type: PyTypeObject;

src/types/dict.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,12 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
232232
key: Bound<'_, PyAny>,
233233
) -> PyResult<Option<Bound<'py, PyAny>>> {
234234
let py = dict.py();
235-
match unsafe {
236-
ffi::PyDict_GetItemWithError(dict.as_ptr(), key.as_ptr())
237-
.assume_borrowed_or_opt(py)
238-
.map(Borrowed::to_owned)
239-
} {
240-
some @ Some(_) => Ok(some),
241-
None => PyErr::take(py).map(Err).transpose(),
235+
unsafe {
236+
let mut result: *mut ffi::PyObject = std::ptr::null_mut();
237+
match ffi::PyDict_GetItemRef(dict.as_ptr(), key.as_ptr(), &mut result) {
238+
std::os::raw::c_int::MIN..=0 => PyErr::take(py).map(Err).transpose(),
239+
1..=std::os::raw::c_int::MAX => Ok(result.assume_owned_or_opt(py)),
240+
}
242241
}
243242
}
244243

0 commit comments

Comments
 (0)