mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +00:00
Issue #22653: Fix an assertion failure in debug mode when doing a reentrant dict insertion in debug mode.
This commit is contained in:
commit
bc92bbd4d2
3 changed files with 35 additions and 3 deletions
|
|
@ -906,6 +906,35 @@ class DictTest(unittest.TestCase):
|
||||||
f.a = 'a'
|
f.a = 'a'
|
||||||
self.assertEqual(f.__dict__, {1:1, 'a':'a'})
|
self.assertEqual(f.__dict__, {1:1, 'a':'a'})
|
||||||
|
|
||||||
|
def check_reentrant_insertion(self, mutate):
|
||||||
|
# This object will trigger mutation of the dict when replaced
|
||||||
|
# by another value. Note this relies on refcounting: the test
|
||||||
|
# won't achieve its purpose on fully-GCed Python implementations.
|
||||||
|
class Mutating:
|
||||||
|
def __del__(self):
|
||||||
|
mutate(d)
|
||||||
|
|
||||||
|
d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
|
||||||
|
for k in list(d):
|
||||||
|
d[k] = k
|
||||||
|
|
||||||
|
def test_reentrant_insertion(self):
|
||||||
|
# Reentrant insertion shouldn't crash (see issue #22653)
|
||||||
|
def mutate(d):
|
||||||
|
d['b'] = 5
|
||||||
|
self.check_reentrant_insertion(mutate)
|
||||||
|
|
||||||
|
def mutate(d):
|
||||||
|
d.update(self.__dict__)
|
||||||
|
d.clear()
|
||||||
|
self.check_reentrant_insertion(mutate)
|
||||||
|
|
||||||
|
def mutate(d):
|
||||||
|
while d:
|
||||||
|
d.popitem()
|
||||||
|
self.check_reentrant_insertion(mutate)
|
||||||
|
|
||||||
|
|
||||||
from test import mapping_tests
|
from test import mapping_tests
|
||||||
|
|
||||||
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
|
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ Release date: TBA
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #22653: Fix an assertion failure in debug mode when doing a reentrant
|
||||||
|
dict insertion in debug mode.
|
||||||
|
|
||||||
- Issue #22643: Fix integer overflow in Unicode case operations (upper, lower,
|
- Issue #22643: Fix integer overflow in Unicode case operations (upper, lower,
|
||||||
title, swapcase, casefold).
|
title, swapcase, casefold).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -814,13 +814,14 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
|
||||||
if (ep == NULL) {
|
if (ep == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
assert(PyUnicode_CheckExact(key) || mp->ma_keys->dk_lookup == lookdict);
|
||||||
Py_INCREF(value);
|
Py_INCREF(value);
|
||||||
MAINTAIN_TRACKING(mp, key, value);
|
MAINTAIN_TRACKING(mp, key, value);
|
||||||
old_value = *value_addr;
|
old_value = *value_addr;
|
||||||
if (old_value != NULL) {
|
if (old_value != NULL) {
|
||||||
assert(ep->me_key != NULL && ep->me_key != dummy);
|
assert(ep->me_key != NULL && ep->me_key != dummy);
|
||||||
*value_addr = value;
|
*value_addr = value;
|
||||||
Py_DECREF(old_value); /* which **CAN** re-enter */
|
Py_DECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ep->me_key == NULL) {
|
if (ep->me_key == NULL) {
|
||||||
|
|
@ -851,9 +852,8 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
|
||||||
}
|
}
|
||||||
mp->ma_used++;
|
mp->ma_used++;
|
||||||
*value_addr = value;
|
*value_addr = value;
|
||||||
|
assert(ep->me_key != NULL && ep->me_key != dummy);
|
||||||
}
|
}
|
||||||
assert(ep->me_key != NULL && ep->me_key != dummy);
|
|
||||||
assert(PyUnicode_CheckExact(key) || mp->ma_keys->dk_lookup == lookdict);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue