summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2015-07-20 11:34:05 (GMT)
committerRaymond Hettinger <python@rcn.com>2015-07-20 11:34:05 (GMT)
commitff9e18a863aa9f7efd894f660d413cd02ccb1834 (patch)
tree0a324d2e1681bbb687f3f5e8aa0d7b42a35b6e68 /Objects
parentaa23fa2e21677c21f5727e6c2602a8bbf67d7fe4 (diff)
downloadcpython-ff9e18a863aa9f7efd894f660d413cd02ccb1834.zip
cpython-ff9e18a863aa9f7efd894f660d413cd02ccb1834.tar.gz
cpython-ff9e18a863aa9f7efd894f660d413cd02ccb1834.tar.bz2
Issue #24583: Consolidate previous set object updates into a single function
with a single entry point, named exit points at the bottom, more self-evident refcount adjustments, and a comment describing why the pre-increment was necessary at all.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/setobject.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 83bff81..3c4c484 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -127,17 +127,27 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
static int set_table_resize(PySetObject *, Py_ssize_t);
static int
-_set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
+set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
{
- setentry *table = so->table;
+ setentry *table;
setentry *freeslot;
setentry *entry;
size_t perturb;
- size_t mask = so->mask;
- size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
+ size_t mask;
+ size_t i; /* Unsigned for defined overflow behavior */
size_t j;
int cmp;
+ /* Pre-increment is necessary to prevent arbitrary code in the rich
+ comparison from deallocating the key just before the insertion. */
+ Py_INCREF(key);
+
+ restart:
+
+ table = so->table;
+ mask = so->mask;
+ i = (size_t)hash & mask;
+
entry = &table[i];
if (entry->key == NULL)
goto found_unused;
@@ -160,9 +170,9 @@ _set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) /* unlikely */
- return -1;
+ goto comparison_error;
if (table != so->table || entry->key != startkey) /* unlikely */
- return _set_add_entry(so, key, hash);
+ goto restart;
if (cmp > 0) /* likely */
goto found_active;
mask = so->mask; /* help avoid a register spill */
@@ -188,9 +198,9 @@ _set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0)
- return -1;
+ goto comparison_error;
if (table != so->table || entry->key != startkey)
- return _set_add_entry(so, key, hash);
+ goto restart;
if (cmp > 0)
goto found_active;
mask = so->mask;
@@ -223,22 +233,13 @@ _set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
entry->hash = hash;
if ((size_t)so->fill*3 < mask*2)
return 0;
- if (!set_table_resize(so, so->used))
- return 0;
- Py_INCREF(key);
- return -1;
+ return set_table_resize(so, so->used);
found_active:
Py_DECREF(key);
return 0;
-}
-static int
-set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
-{
- Py_INCREF(key);
- if (!_set_add_entry(so, key, hash))
- return 0;
+ comparison_error:
Py_DECREF(key);
return -1;
}