Skip to content

Commit 5e6e432

Browse files
Add PyList_GetItemRef and use it in list.get_item (#4410)
* Add PyList_GetItemRef bindings and compat shim * Use PyList_GetItemRef in list.get_item() * add release notes * apply code review comments * Update newsfragments/4410.added.md Co-authored-by: David Hewitt <[email protected]> * apply `all()` doc cfg hints --------- Co-authored-by: David Hewitt <[email protected]>
1 parent d103c76 commit 5e6e432

File tree

5 files changed

+26
-7
lines changed

5 files changed

+26
-7
lines changed

newsfragments/4410.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add ffi binding `PyList_GetItemRef` and `pyo3_ffi::compat::PyList_GetItemRef`

newsfragments/4410.fixed.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
* Avoid creating temporary borrowed reference in list.get_item
2+
bindings. Temporary borrowed references are unsafe in the free-threaded python
3+
build if the list is shared between threads.

pyo3-ffi/src/compat.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
#[cfg(not(Py_3_13))]
1313
use crate::object::PyObject;
1414
#[cfg(not(Py_3_13))]
15+
use crate::pyport::Py_ssize_t;
16+
#[cfg(not(Py_3_13))]
1517
use std::os::raw::c_int;
1618

17-
#[cfg_attr(docsrs, doc(cfg(all)))]
19+
#[cfg_attr(docsrs, doc(cfg(all())))]
1820
#[cfg(Py_3_13)]
1921
pub use crate::dictobject::PyDict_GetItemRef;
2022

21-
#[cfg_attr(docsrs, doc(cfg(all)))]
23+
#[cfg_attr(docsrs, doc(cfg(all())))]
2224
#[cfg(not(Py_3_13))]
2325
pub unsafe fn PyDict_GetItemRef(
2426
dp: *mut PyObject,
@@ -42,3 +44,17 @@ pub unsafe fn PyDict_GetItemRef(
4244
-1
4345
}
4446
}
47+
48+
#[cfg_attr(docsrs, doc(cfg(all())))]
49+
#[cfg(Py_3_13)]
50+
pub use crate::PyList_GetItemRef;
51+
52+
#[cfg(not(Py_3_13))]
53+
#[cfg_attr(docsrs, doc(cfg(all())))]
54+
pub unsafe fn PyList_GetItemRef(arg1: *mut PyObject, arg2: Py_ssize_t) -> *mut PyObject {
55+
use crate::{PyList_GetItem, Py_XINCREF};
56+
57+
let item: *mut PyObject = PyList_GetItem(arg1, arg2);
58+
Py_XINCREF(item);
59+
item
60+
}

pyo3-ffi/src/listobject.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ extern "C" {
2828
pub fn PyList_Size(arg1: *mut PyObject) -> Py_ssize_t;
2929
#[cfg_attr(PyPy, link_name = "PyPyList_GetItem")]
3030
pub fn PyList_GetItem(arg1: *mut PyObject, arg2: Py_ssize_t) -> *mut PyObject;
31+
#[cfg(Py_3_13)]
32+
pub fn PyList_GetItemRef(arg1: *mut PyObject, arg2: Py_ssize_t) -> *mut PyObject;
3133
#[cfg_attr(PyPy, link_name = "PyPyList_SetItem")]
3234
pub fn PyList_SetItem(arg1: *mut PyObject, arg2: Py_ssize_t, arg3: *mut PyObject) -> c_int;
3335
#[cfg_attr(PyPy, link_name = "PyPyList_Insert")]

src/types/list.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::iter::FusedIterator;
33
use crate::err::{self, PyResult};
44
use crate::ffi::{self, Py_ssize_t};
55
use crate::ffi_ptr_ext::FfiPtrExt;
6-
use crate::instance::Borrowed;
76
use crate::internal_tricks::get_ssize_index;
87
use crate::types::{PySequence, PyTuple};
98
#[cfg(feature = "gil-refs")]
@@ -434,10 +433,8 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
434433
/// ```
435434
fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
436435
unsafe {
437-
// PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
438-
ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)
439-
.assume_borrowed_or_err(self.py())
440-
.map(Borrowed::to_owned)
436+
ffi::compat::PyList_GetItemRef(self.as_ptr(), index as Py_ssize_t)
437+
.assume_owned_or_err(self.py())
441438
}
442439
}
443440

0 commit comments

Comments
 (0)