mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +00:00
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:
parent
204946986f
commit
4a66615ba7
3 changed files with 226 additions and 8 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue