Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4804991

Browse files
committed
Fix obscure set crashers (#8420). Backport of d56b3cafb1e6, reviewed by Raymond.
1 parent c706dbf commit 4804991

2 files changed

Lines changed: 57 additions & 10 deletions

File tree

Lib/test/test_set.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,39 @@ def test_inplace_methods(self):
16601660
self.assertRaises(TypeError, getattr(set('january'), methname), N(data))
16611661
self.assertRaises(ZeroDivisionError, getattr(set('january'), methname), E(data))
16621662

1663+
class bad_eq:
1664+
def __eq__(self, other):
1665+
if be_bad:
1666+
set2.clear()
1667+
raise ZeroDivisionError
1668+
return self is other
1669+
def __hash__(self):
1670+
return 0
1671+
1672+
class bad_dict_clear:
1673+
def __eq__(self, other):
1674+
if be_bad:
1675+
dict2.clear()
1676+
return self is other
1677+
def __hash__(self):
1678+
return 0
1679+
1680+
class TestWeirdBugs(unittest.TestCase):
1681+
def test_8420_set_merge(self):
1682+
# This used to segfault
1683+
global be_bad, set2, dict2
1684+
be_bad = False
1685+
set1 = {bad_eq()}
1686+
set2 = {bad_eq() for i in range(75)}
1687+
be_bad = True
1688+
self.assertRaises(ZeroDivisionError, set1.update, set2)
1689+
1690+
be_bad = False
1691+
set1 = {bad_dict_clear()}
1692+
dict2 = {bad_dict_clear(): None}
1693+
be_bad = True
1694+
set1.symmetric_difference_update(dict2)
1695+
16631696
# Application tests (based on David Eppstein's graph recipes ====================================
16641697

16651698
def powerset(U):
@@ -1804,6 +1837,7 @@ def test_main(verbose=None):
18041837
TestIdentities,
18051838
TestVariousIteratorArgs,
18061839
TestGraphs,
1840+
TestWeirdBugs,
18071841
)
18081842

18091843
support.run_unittest(*test_classes)

Objects/setobject.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -364,12 +364,14 @@ static int
364364
set_add_entry(register PySetObject *so, setentry *entry)
365365
{
366366
register Py_ssize_t n_used;
367+
PyObject *key = entry->key;
368+
long hash = entry->hash;
367369

368370
assert(so->fill <= so->mask); /* at least one empty slot */
369371
n_used = so->used;
370-
Py_INCREF(entry->key);
371-
if (set_insert_key(so, entry->key, (long) entry->hash) == -1) {
372-
Py_DECREF(entry->key);
372+
Py_INCREF(key);
373+
if (set_insert_key(so, key, hash) == -1) {
374+
Py_DECREF(key);
373375
return -1;
374376
}
375377
if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2))
@@ -637,6 +639,8 @@ static int
637639
set_merge(PySetObject *so, PyObject *otherset)
638640
{
639641
PySetObject *other;
642+
PyObject *key;
643+
long hash;
640644
register Py_ssize_t i;
641645
register setentry *entry;
642646

@@ -657,11 +661,13 @@ set_merge(PySetObject *so, PyObject *otherset)
657661
}
658662
for (i = 0; i <= other->mask; i++) {
659663
entry = &other->table[i];
660-
if (entry->key != NULL &&
661-
entry->key != dummy) {
662-
Py_INCREF(entry->key);
663-
if (set_insert_key(so, entry->key, (long) entry->hash) == -1) {
664-
Py_DECREF(entry->key);
664+
key = entry->key;
665+
hash = entry->hash;
666+
if (key != NULL &&
667+
key != dummy) {
668+
Py_INCREF(key);
669+
if (set_insert_key(so, key, hash) == -1) {
670+
Py_DECREF(key);
665671
return -1;
666672
}
667673
}
@@ -1642,15 +1648,22 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
16421648
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
16431649
setentry an_entry;
16441650

1651+
Py_INCREF(key);
16451652
an_entry.hash = hash;
16461653
an_entry.key = key;
1654+
16471655
rv = set_discard_entry(so, &an_entry);
1648-
if (rv == -1)
1656+
if (rv == -1) {
1657+
Py_DECREF(key);
16491658
return NULL;
1659+
}
16501660
if (rv == DISCARD_NOTFOUND) {
1651-
if (set_add_entry(so, &an_entry) == -1)
1661+
if (set_add_entry(so, &an_entry) == -1) {
1662+
Py_DECREF(key);
16521663
return NULL;
1664+
}
16531665
}
1666+
Py_DECREF(key);
16541667
}
16551668
Py_RETURN_NONE;
16561669
}

0 commit comments

Comments
 (0)