From afab9b299607761b54a3c8dbe6531d8456b99eea Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 3 Sep 2024 18:04:01 +0200 Subject: [PATCH] Copy dict on free-threaded builds to prevent concurrent modifications --- src/types/dict.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/types/dict.rs b/src/types/dict.rs index 26df028516a..36b96a70bd9 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -378,7 +378,6 @@ pub enum BoundDictIterator<'py> { /// Iterator over the items of the dictionary, using the C-API `PyDict_Next`. This variant is /// only used when the dictionary is an exact instance of `PyDict` and the GIL enabled. #[allow(missing_docs)] - #[cfg(not(Py_GIL_DISABLED))] DictIter { dict: Bound<'py, PyDict>, ppos: ffi::Py_ssize_t, @@ -402,7 +401,6 @@ impl<'py> Iterator for BoundDictIterator<'py> { (key, value) }) } - #[cfg(not(Py_GIL_DISABLED))] BoundDictIterator::DictIter { dict, ppos, @@ -466,7 +464,6 @@ impl<'py> ExactSizeIterator for BoundDictIterator<'py> { fn len(&self) -> usize { match self { BoundDictIterator::ItemIter { remaining, .. } => *remaining as usize, - #[cfg(not(Py_GIL_DISABLED))] BoundDictIterator::DictIter { remaining, .. } => *remaining as usize, } } @@ -476,8 +473,12 @@ impl<'py> BoundDictIterator<'py> { fn new(dict: Bound<'py, PyDict>) -> Self { let remaining = dict_len(&dict); - #[cfg(not(Py_GIL_DISABLED))] if dict.is_exact_instance_of::() { + // Copy the dictionary if the GIL is disabled, as we can't guarantee that the dictionary + // won't be modified during iteration. + #[cfg(Py_GIL_DISABLED)] + let dict = dict.copy().unwrap(); + return BoundDictIterator::DictIter { dict, ppos: 0,