[3.6] bpo-27945: Fixed various segfaults with dict. (GH-1657) (#1677)
Based on patches by Duane Griffin and Tim Mitchell.
(cherry picked from commit 753bca3934a7618a4fa96e107ad1c5c18633a683)
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 566d1a5..b0f583a 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1115,18 +1115,18 @@
PyDictKeyEntry *ep, *ep0;
Py_ssize_t hashpos, ix;
+ Py_INCREF(key);
+ Py_INCREF(value);
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp) < 0)
- return -1;
+ goto Fail;
}
ix = mp->ma_keys->dk_lookup(mp, key, hash, &value_addr, &hashpos);
- if (ix == DKIX_ERROR) {
- return -1;
- }
+ if (ix == DKIX_ERROR)
+ goto Fail;
assert(PyUnicode_CheckExact(key) || mp->ma_keys->dk_lookup == lookdict);
- Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value);
/* When insertion order is different from shared key, we can't share
@@ -1135,10 +1135,8 @@
if (_PyDict_HasSplitTable(mp) &&
((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) ||
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
- if (insertion_resize(mp) < 0) {
- Py_DECREF(value);
- return -1;
- }
+ if (insertion_resize(mp) < 0)
+ goto Fail;
find_empty_slot(mp, key, hash, &value_addr, &hashpos);
ix = DKIX_EMPTY;
}
@@ -1147,16 +1145,13 @@
/* Insert into new slot. */
if (mp->ma_keys->dk_usable <= 0) {
/* Need to resize. */
- if (insertion_resize(mp) < 0) {
- Py_DECREF(value);
- return -1;
- }
+ if (insertion_resize(mp) < 0)
+ goto Fail;
find_empty_slot(mp, key, hash, &value_addr, &hashpos);
}
ep0 = DK_ENTRIES(mp->ma_keys);
ep = &ep0[mp->ma_keys->dk_nentries];
dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
- Py_INCREF(key);
ep->me_key = key;
ep->me_hash = hash;
if (mp->ma_values) {
@@ -1184,6 +1179,7 @@
assert(_PyDict_CheckConsistency(mp));
Py_DECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
+ Py_DECREF(key);
return 0;
}
@@ -1194,7 +1190,13 @@
mp->ma_used++;
mp->ma_version_tag = DICT_NEXT_VERSION();
assert(_PyDict_CheckConsistency(mp));
+ Py_DECREF(key);
return 0;
+
+Fail:
+ Py_DECREF(value);
+ Py_DECREF(key);
+ return -1;
}
/*
@@ -2432,11 +2434,18 @@
/* Update/merge with this (key, value) pair. */
key = PySequence_Fast_GET_ITEM(fast, 0);
value = PySequence_Fast_GET_ITEM(fast, 1);
+ Py_INCREF(key);
+ Py_INCREF(value);
if (override || PyDict_GetItem(d, key) == NULL) {
int status = PyDict_SetItem(d, key, value);
- if (status < 0)
+ if (status < 0) {
+ Py_DECREF(key);
+ Py_DECREF(value);
goto Fail;
+ }
}
+ Py_DECREF(key);
+ Py_DECREF(value);
Py_DECREF(fast);
Py_DECREF(item);
}
@@ -2737,14 +2746,15 @@
bval = NULL;
else
bval = *vaddr;
- Py_DECREF(key);
if (bval == NULL) {
+ Py_DECREF(key);
Py_DECREF(aval);
if (PyErr_Occurred())
return -1;
return 0;
}
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
+ Py_DECREF(key);
Py_DECREF(aval);
if (cmp <= 0) /* error or not equal */
return cmp;
@@ -3633,7 +3643,7 @@
static PyObject *
dictiter_iternextitem(dictiterobject *di)
{
- PyObject *key, *value, *result = di->di_result;
+ PyObject *key, *value, *result;
Py_ssize_t i, n;
PyDictObject *d = di->di_dict;
@@ -3674,20 +3684,25 @@
}
di->di_pos = i+1;
di->len--;
- if (result->ob_refcnt == 1) {
+ Py_INCREF(key);
+ Py_INCREF(value);
+ result = di->di_result;
+ if (Py_REFCNT(result) == 1) {
+ PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
+ PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
+ PyTuple_SET_ITEM(result, 0, key); /* steals reference */
+ PyTuple_SET_ITEM(result, 1, value); /* steals reference */
Py_INCREF(result);
- Py_DECREF(PyTuple_GET_ITEM(result, 0));
- Py_DECREF(PyTuple_GET_ITEM(result, 1));
+ Py_DECREF(oldkey);
+ Py_DECREF(oldvalue);
}
else {
result = PyTuple_New(2);
if (result == NULL)
return NULL;
+ PyTuple_SET_ITEM(result, 0, key); /* steals reference */
+ PyTuple_SET_ITEM(result, 1, value); /* steals reference */
}
- Py_INCREF(key);
- Py_INCREF(value);
- PyTuple_SET_ITEM(result, 0, key); /* steals reference */
- PyTuple_SET_ITEM(result, 1, value); /* steals reference */
return result;
fail:
@@ -4180,6 +4195,7 @@
static int
dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
{
+ int result;
PyObject *key, *value, *found;
if (dv->dv_dict == NULL)
return 0;
@@ -4193,7 +4209,10 @@
return -1;
return 0;
}
- return PyObject_RichCompareBool(value, found, Py_EQ);
+ Py_INCREF(found);
+ result = PyObject_RichCompareBool(value, found, Py_EQ);
+ Py_DECREF(found);
+ return result;
}
static PySequenceMethods dictitems_as_sequence = {