diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 8ef2871c61..f7fc65512c 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1809,7 +1809,6 @@ def check_set_op_does_not_crash(self, function): self.assertIn("changed size during iteration", str(e)) -@unittest.skip("TODO: RUSTPYTHON; segfault") class TestBinaryOpsMutating(TestOperationsMutating): def test_eq_with_mutation(self): @@ -1898,7 +1897,6 @@ class TestBinaryOpsMutating_Subclass_Set(TestBinaryOpsMutating, unittest.TestCas constructor2 = set -@unittest.skip("TODO: RUSTPYTHON; segfault") class TestMethodsMutating(TestOperationsMutating): def test_issubset_with_mutation(self): diff --git a/vm/src/dict_inner.rs b/vm/src/dict_inner.rs index 02e237afb0..f62e31e243 100644 --- a/vm/src/dict_inner.rs +++ b/vm/src/dict_inner.rs @@ -574,6 +574,7 @@ impl Dict { ) -> PyResult { let mut idxs = None; let mut free_slot = None; + let original_size = self.size(); let ret = 'outer: loop { let (entry_key, ret) = { let inner = lock.take().unwrap_or_else(|| self.read()); @@ -582,9 +583,12 @@ impl Dict { }); loop { let index_index = idxs.next(); - let index_entry = *unsafe { - // Safety: index_index is generated - inner.indices.get_unchecked(index_index) + let index_entry = match inner.indices.get(index_index) { + None => { + // Dictionary was modified under our hands, see TestMethodsMutating. + return Err(vm.new_runtime_error("set changed size during iteration")); + } + Some(v) => *v, }; match index_entry { IndexEntry::DUMMY => { @@ -597,6 +601,11 @@ impl Dict { Some(free) => (IndexEntry::DUMMY, free), None => (IndexEntry::FREE, index_index), }; + if self.has_changed_size(&original_size) { + return Err( + vm.new_runtime_error("set changed size during iteration") + ); + } return Ok(idxs); } idx => { @@ -628,6 +637,9 @@ impl Dict { // warn!("Perturb value: {}", i); }; + if self.has_changed_size(&original_size) { + return Err(vm.new_runtime_error("set changed size during iteration")); + } Ok(ret) }