summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2016-09-10 02:28:36 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2016-09-10 02:28:36 (GMT)
commit78601a38c22ba1f09104e2562a10a94cbd36f5f0 (patch)
tree1abadfbcec51e16790781cbe045eaa6de6b91478 /Objects
parenteb0dfa9251102e42bdabcb84de17cecb43537442 (diff)
downloadcpython-78601a38c22ba1f09104e2562a10a94cbd36f5f0.zip
cpython-78601a38c22ba1f09104e2562a10a94cbd36f5f0.tar.gz
cpython-78601a38c22ba1f09104e2562a10a94cbd36f5f0.tar.bz2
Fix SystemError in compact dict
Issue #28040: Fix _PyDict_DelItem_KnownHash() and _PyDict_Pop(): convert splitted table to combined table to be able to delete the item. Write an unit test for the issue. Patch by INADA Naoki.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c52
1 files changed, 33 insertions, 19 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 461eb57..8a13fb4 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1546,21 +1546,27 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
return -1;
}
assert(dk_get_index(mp->ma_keys, hashpos) == ix);
+
+ // Split table doesn't allow deletion. Combine it.
+ if (_PyDict_HasSplitTable(mp)) {
+ if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
+ return -1;
+ }
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ assert(ix >= 0);
+ }
+
old_value = *value_addr;
+ assert(old_value != NULL);
*value_addr = NULL;
mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION();
- if (_PyDict_HasSplitTable(mp)) {
- mp->ma_keys->dk_usable = 0;
- }
- else {
- ep = &DK_ENTRIES(mp->ma_keys)[ix];
- dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
- ENSURE_ALLOWS_DELETIONS(mp);
- old_key = ep->me_key;
- ep->me_key = NULL;
- Py_DECREF(old_key);
- }
+ ep = &DK_ENTRIES(mp->ma_keys)[ix];
+ dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
+ ENSURE_ALLOWS_DELETIONS(mp);
+ old_key = ep->me_key;
+ ep->me_key = NULL;
+ Py_DECREF(old_key);
Py_DECREF(old_value);
return 0;
}
@@ -1725,18 +1731,26 @@ _PyDict_Pop(PyDictObject *mp, PyObject *key, PyObject *deflt)
return NULL;
}
+ // Split table doesn't allow deletion. Combine it.
+ if (_PyDict_HasSplitTable(mp)) {
+ if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
+ return NULL;
+ }
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ assert(ix >= 0);
+ }
+
old_value = *value_addr;
+ assert(old_value != NULL);
*value_addr = NULL;
mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION();
- if (!_PyDict_HasSplitTable(mp)) {
- dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
- ep = &DK_ENTRIES(mp->ma_keys)[ix];
- ENSURE_ALLOWS_DELETIONS(mp);
- old_key = ep->me_key;
- ep->me_key = NULL;
- Py_DECREF(old_key);
- }
+ dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
+ ep = &DK_ENTRIES(mp->ma_keys)[ix];
+ ENSURE_ALLOWS_DELETIONS(mp);
+ old_key = ep->me_key;
+ ep->me_key = NULL;
+ Py_DECREF(old_key);
return old_value;
}