bpo-46615: Don't crash when set operations mutate the sets (GH-31120)

Ensure strong references are acquired whenever using `set_next()`. Added randomized test cases for `__eq__` methods that sometimes mutate sets when called.
This commit is contained in:
Dennis Sweeney 2022-02-11 11:25:08 -05:00 committed by GitHub
parent 204946986f
commit 4a66615ba7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 226 additions and 8 deletions

View file

@ -1205,17 +1205,21 @@ set_intersection(PySetObject *so, PyObject *other)
while (set_next((PySetObject *)other, &pos, &entry)) {
key = entry->key;
hash = entry->hash;
Py_INCREF(key);
rv = set_contains_entry(so, key, hash);
if (rv < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
if (rv) {
if (set_add_entry(result, key, hash)) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
}
Py_DECREF(key);
}
return (PyObject *)result;
}
@ -1355,11 +1359,16 @@ set_isdisjoint(PySetObject *so, PyObject *other)
other = tmp;
}
while (set_next((PySetObject *)other, &pos, &entry)) {
rv = set_contains_entry(so, entry->key, entry->hash);
if (rv < 0)
PyObject *key = entry->key;
Py_INCREF(key);
rv = set_contains_entry(so, key, entry->hash);
Py_DECREF(key);
if (rv < 0) {
return NULL;
if (rv)
}
if (rv) {
Py_RETURN_FALSE;
}
}
Py_RETURN_TRUE;
}
@ -1418,11 +1427,16 @@ set_difference_update_internal(PySetObject *so, PyObject *other)
Py_INCREF(other);
}
while (set_next((PySetObject *)other, &pos, &entry))
if (set_discard_entry(so, entry->key, entry->hash) < 0) {
while (set_next((PySetObject *)other, &pos, &entry)) {
PyObject *key = entry->key;
Py_INCREF(key);
if (set_discard_entry(so, key, entry->hash) < 0) {
Py_DECREF(other);
Py_DECREF(key);
return -1;
}
Py_DECREF(key);
}
Py_DECREF(other);
} else {
@ -1513,17 +1527,21 @@ set_difference(PySetObject *so, PyObject *other)
while (set_next(so, &pos, &entry)) {
key = entry->key;
hash = entry->hash;
Py_INCREF(key);
rv = _PyDict_Contains_KnownHash(other, key, hash);
if (rv < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
if (!rv) {
if (set_add_entry((PySetObject *)result, key, hash)) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
}
Py_DECREF(key);
}
return result;
}
@ -1532,17 +1550,21 @@ set_difference(PySetObject *so, PyObject *other)
while (set_next(so, &pos, &entry)) {
key = entry->key;
hash = entry->hash;
Py_INCREF(key);
rv = set_contains_entry((PySetObject *)other, key, hash);
if (rv < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
if (!rv) {
if (set_add_entry((PySetObject *)result, key, hash)) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
}
Py_DECREF(key);
}
return result;
}
@ -1639,17 +1661,21 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
while (set_next(otherset, &pos, &entry)) {
key = entry->key;
hash = entry->hash;
Py_INCREF(key);
rv = set_discard_entry(so, key, hash);
if (rv < 0) {
Py_DECREF(otherset);
Py_DECREF(key);
return NULL;
}
if (rv == DISCARD_NOTFOUND) {
if (set_add_entry(so, key, hash)) {
Py_DECREF(otherset);
Py_DECREF(key);
return NULL;
}
}
Py_DECREF(key);
}
Py_DECREF(otherset);
Py_RETURN_NONE;
@ -1724,11 +1750,16 @@ set_issubset(PySetObject *so, PyObject *other)
Py_RETURN_FALSE;
while (set_next(so, &pos, &entry)) {
rv = set_contains_entry((PySetObject *)other, entry->key, entry->hash);
if (rv < 0)
PyObject *key = entry->key;
Py_INCREF(key);
rv = set_contains_entry((PySetObject *)other, key, entry->hash);
Py_DECREF(key);
if (rv < 0) {
return NULL;
if (!rv)
}
if (!rv) {
Py_RETURN_FALSE;
}
}
Py_RETURN_TRUE;
}