Skip to content

Commit 69e4dab

Browse files
committed
Add bindings for PyDict_SetDefaultRef and use them in PyCode::run
1 parent 35c8f24 commit 69e4dab

4 files changed

Lines changed: 70 additions & 21 deletions

File tree

pyo3-ffi/src/compat/py_3_13.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,51 @@ compat_function!(
130130
crate::_PyThreadState_UncheckedGet()
131131
}
132132
);
133+
134+
compat_function! {
135+
originally_defined_for(any(Py_3_13, all(Py_LIMITED_API, Py_3_15)));
136+
137+
#[inline]
138+
pub unsafe fn PyDict_SetDefaultRef(
139+
mp: *mut crate::PyObject,
140+
key: *mut crate::PyObject,
141+
default_value: *mut crate::PyObject,
142+
result: *mut *mut crate::PyObject,
143+
) -> std::ffi::c_int {
144+
use crate::{
145+
compat::{PyDict_GetItemRef, Py_NewRef},
146+
PyDict_SetItem, PyObject, Py_DECREF,
147+
};
148+
let mut value: *mut PyObject = std::ptr::null_mut();
149+
if PyDict_GetItemRef(mp, key, &mut value) < 0 {
150+
// get error
151+
if !result.is_null() {
152+
*result = std::ptr::null_mut();
153+
}
154+
return -1;
155+
}
156+
if !value.is_null() {
157+
// present
158+
if !result.is_null() {
159+
*result = value;
160+
}
161+
else {
162+
Py_DECREF(value);
163+
}
164+
return 1;
165+
}
166+
167+
// missing, set the item
168+
if PyDict_SetItem(mp, key, default_value) < 0 {
169+
// set error
170+
if !result.is_null() {
171+
*result = std::ptr::null_mut();
172+
}
173+
return -1;
174+
}
175+
if !result.is_null() {
176+
*result = Py_NewRef(default_value);
177+
}
178+
return 0;
179+
}
180+
}

pyo3-ffi/src/cpython/dictobject.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ pub struct PyDictObject {
4343
// skipped private _PyDict_GetItemStringWithError
4444

4545
// skipped PyDict_SetDefault
46-
// skipped PyDict_SetDefaultRef
4746

4847
// skipped PyDict_GET_SIZE
4948
// skipped PyDict_ContainsString

pyo3-ffi/src/dictobject.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ extern_libpython! {
7878
key: *const c_char,
7979
result: *mut *mut PyObject,
8080
) -> c_int;
81+
#[cfg(any(Py_3_13, all(Py_LIMITED_API, Py_3_15)))]
82+
pub fn PyDict_SetDefaultRef(
83+
mp: *mut PyObject,
84+
key: *mut PyObject,
85+
default_value: *mut PyObject,
86+
result: *mut *mut PyObject,
87+
) -> c_int;
8188
// skipped 3.10 / ex-non-limited PyObject_GenericGetDict
8289
}
8390

src/types/code.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -127,28 +127,23 @@ impl<'py> PyCodeMethods<'py> for Bound<'py, PyCode> {
127127
// - https://github.com/python/cpython/pull/24564 (the same fix in CPython 3.10)
128128
// - https://github.com/PyO3/pyo3/issues/3370
129129
let builtins_s = crate::intern!(self.py(), "__builtins__");
130-
let has_builtins = globals.contains(builtins_s)?;
131-
if !has_builtins {
132-
crate::sync::critical_section::with_critical_section(globals, || {
133-
// check if another thread set __builtins__ while this thread was blocked on the critical section
134-
let has_builtins = globals.contains(builtins_s)?;
135-
if !has_builtins {
136-
// Inherit current builtins.
137-
let builtins = unsafe { ffi::PyEval_GetBuiltins() };
138-
139-
// `PyDict_SetItem` doesn't take ownership of `builtins`, but `PyEval_GetBuiltins`
140-
// seems to return a borrowed reference, so no leak here.
141-
if unsafe {
142-
ffi::PyDict_SetItem(globals.as_ptr(), builtins_s.as_ptr(), builtins)
143-
} == -1
144-
{
145-
return Err(PyErr::fetch(self.py()));
146-
}
147-
}
148-
Ok(())
149-
})?;
130+
let mut result: *mut ffi::PyObject = std::ptr::null_mut();
131+
if unsafe {
132+
ffi::compat::PyDict_SetDefaultRef(
133+
globals.as_ptr(),
134+
builtins_s.as_ptr(),
135+
// borrowed reference
136+
ffi::PyEval_GetBuiltins(),
137+
&mut result,
138+
)
139+
} == -1
140+
{
141+
return Err(PyErr::fetch(self.py()));
150142
}
151143

144+
// release ownership of result
145+
unsafe { ffi::Py_DECREF(result) };
146+
152147
unsafe {
153148
ffi::PyEval_EvalCode(self.as_ptr(), globals.as_ptr(), locals.as_ptr())
154149
.assume_owned_or_err(self.py())

0 commit comments

Comments
 (0)