From d13e735fa34a2955eb6c337626259df7322fb654 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Mon, 15 Jan 2024 12:01:49 +0000 Subject: [PATCH] force index call for PyLong_AsUnsignedLongLong --- src/conversions/std/num.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 19829797e51..8bad4bd6894 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -46,10 +46,15 @@ macro_rules! int_fits_larger_int { macro_rules! extract_int { ($obj:ident, $error_val:expr, $pylong_as:expr) => { + extract_int!($obj, $error_val, $pylong_as, false) + }; + + ($obj:ident, $error_val:expr, $pylong_as:expr, $force_index_call: literal) => { // with python 3.8+ PyLong_AsLong takes care of calling PyNumber_Index itself // hence no need for the slow `PyNumber_Index` path + // `PyLong_AsUnsignedLongLong` does not call `__index__`, hence the `force_index_call` argument // see https://github.com/PyO3/pyo3/pull/3742 for detials. - if cfg!(Py_3_8) { + if cfg!(Py_3_8) && !$force_index_call { err_if_invalid_value($obj.py(), $error_val, unsafe { $pylong_as($obj.as_ptr()) }) } else if let Ok(long) = $obj.downcast::() { // with 3.7 we have to do the `PyNumber_Index` check ourselves @@ -71,7 +76,7 @@ macro_rules! extract_int { } macro_rules! int_convert_u64_or_i64 { - ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr) => { + ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr, $force_index_call:literal) => { impl ToPyObject for $rust_type { #[inline] fn to_object(&self, py: Python<'_>) -> PyObject { @@ -91,7 +96,7 @@ macro_rules! int_convert_u64_or_i64 { } impl<'source> FromPyObject<'source> for $rust_type { fn extract(obj: &'source PyAny) -> PyResult<$rust_type> { - extract_int!(obj, !0, $pylong_as_ll_or_ull) + extract_int!(obj, !0, $pylong_as_ll_or_ull, $force_index_call) } #[cfg(feature = "experimental-inspect")] @@ -152,7 +157,7 @@ int_fits_c_long!(i64); // manual implementation for i64 on systems with 32-bit long #[cfg(any(target_pointer_width = "32", target_os = "windows"))] -int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong); +int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong, false); #[cfg(all(target_pointer_width = "64", not(target_os = "windows")))] int_fits_c_long!(isize); @@ -165,7 +170,8 @@ int_fits_larger_int!(usize, u64); int_convert_u64_or_i64!( u64, ffi::PyLong_FromUnsignedLongLong, - ffi::PyLong_AsUnsignedLongLong + ffi::PyLong_AsUnsignedLongLong, + true ); #[cfg(not(Py_LIMITED_API))]