mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Fix dict race condition (#6720)
This commit is contained in:
@@ -62,6 +62,24 @@ impl PyDict {
|
||||
&self.entries
|
||||
}
|
||||
|
||||
/// Returns all keys as a Vec, atomically under a single read lock.
|
||||
/// Thread-safe: prevents "dictionary changed size during iteration" errors.
|
||||
pub fn keys_vec(&self) -> Vec<PyObjectRef> {
|
||||
self.entries.keys()
|
||||
}
|
||||
|
||||
/// Returns all values as a Vec, atomically under a single read lock.
|
||||
/// Thread-safe: prevents "dictionary changed size during iteration" errors.
|
||||
pub fn values_vec(&self) -> Vec<PyObjectRef> {
|
||||
self.entries.values()
|
||||
}
|
||||
|
||||
/// Returns all items as a Vec, atomically under a single read lock.
|
||||
/// Thread-safe: prevents "dictionary changed size during iteration" errors.
|
||||
pub fn items_vec(&self) -> Vec<(PyObjectRef, PyObjectRef)> {
|
||||
self.entries.items()
|
||||
}
|
||||
|
||||
// Used in update and ior.
|
||||
pub(crate) fn merge_object(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let casted: Result<PyRefExact<Self>, _> = other.downcast_exact(vm);
|
||||
|
||||
@@ -553,6 +553,22 @@ impl<T: Clone> Dict<T> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Vec<T> {
|
||||
self.read()
|
||||
.entries
|
||||
.iter()
|
||||
.filter_map(|v| v.as_ref().map(|v| v.value.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn items(&self) -> Vec<(PyObjectRef, T)> {
|
||||
self.read()
|
||||
.entries
|
||||
.iter()
|
||||
.filter_map(|v| v.as_ref().map(|v| (v.key.clone(), v.value.clone())))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn try_fold_keys<Acc, Fold>(&self, init: Acc, f: Fold) -> PyResult<Acc>
|
||||
where
|
||||
Fold: FnMut(Acc, &PyObject) -> PyResult<Acc>,
|
||||
|
||||
@@ -20,7 +20,11 @@ use crate::{
|
||||
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
|
||||
builtins::{
|
||||
PyBaseExceptionRef, PyDict, PyDictRef, PyInt, PyList, PyModule, PyStr, PyStrInterned,
|
||||
PyStrRef, PyTypeRef, code::PyCode, pystr::AsPyStr, tuple::PyTuple,
|
||||
PyStrRef, PyTypeRef,
|
||||
code::PyCode,
|
||||
dict::{PyDictItems, PyDictKeys, PyDictValues},
|
||||
pystr::AsPyStr,
|
||||
tuple::PyTuple,
|
||||
},
|
||||
codecs::CodecsRegistry,
|
||||
common::{hash::HashSecret, lock::PyMutex, rc::PyRc},
|
||||
@@ -808,6 +812,29 @@ impl VirtualMachine {
|
||||
} else if cls.is(self.ctx.types.list_type) {
|
||||
list_borrow = value.downcast_ref::<PyList>().unwrap().borrow_vec();
|
||||
&list_borrow
|
||||
} else if cls.is(self.ctx.types.dict_keys_type) {
|
||||
// Atomic snapshot of dict keys - prevents race condition during iteration
|
||||
let keys = value.downcast_ref::<PyDictKeys>().unwrap().dict.keys_vec();
|
||||
return keys.into_iter().map(func).collect();
|
||||
} else if cls.is(self.ctx.types.dict_values_type) {
|
||||
// Atomic snapshot of dict values - prevents race condition during iteration
|
||||
let values = value
|
||||
.downcast_ref::<PyDictValues>()
|
||||
.unwrap()
|
||||
.dict
|
||||
.values_vec();
|
||||
return values.into_iter().map(func).collect();
|
||||
} else if cls.is(self.ctx.types.dict_items_type) {
|
||||
// Atomic snapshot of dict items - prevents race condition during iteration
|
||||
let items = value
|
||||
.downcast_ref::<PyDictItems>()
|
||||
.unwrap()
|
||||
.dict
|
||||
.items_vec();
|
||||
return items
|
||||
.into_iter()
|
||||
.map(|(k, v)| func(self.ctx.new_tuple(vec![k, v]).into()))
|
||||
.collect();
|
||||
} else {
|
||||
return self.map_py_iter(value, func);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user