bpo-38525: Fix a segmentation fault when using reverse iterators of empty dict (GH-16846)
The reverse iterator for empty dictionaries was not handling correctly shared-key dictionaries.
This commit is contained in:
parent
88eeda6311
commit
24dc2f8c56
|
@ -1312,6 +1312,31 @@ class DictTest(unittest.TestCase):
|
|||
self.assertEqual(list(r), list('dcba'))
|
||||
self.assertRaises(StopIteration, next, r)
|
||||
|
||||
def test_reverse_iterator_for_empty_dict(self):
|
||||
# bpo-38525: revered iterator should work properly
|
||||
|
||||
# empty dict is directly used for reference count test
|
||||
self.assertEqual(list(reversed({})), [])
|
||||
self.assertEqual(list(reversed({}.items())), [])
|
||||
self.assertEqual(list(reversed({}.values())), [])
|
||||
self.assertEqual(list(reversed({}.keys())), [])
|
||||
|
||||
# dict() and {} don't trigger the same code path
|
||||
self.assertEqual(list(reversed(dict())), [])
|
||||
self.assertEqual(list(reversed(dict().items())), [])
|
||||
self.assertEqual(list(reversed(dict().values())), [])
|
||||
self.assertEqual(list(reversed(dict().keys())), [])
|
||||
|
||||
def test_reverse_iterator_for_shared_shared_dicts(self):
|
||||
class A:
|
||||
def __init__(self, x, y):
|
||||
if x: self.x = x
|
||||
if y: self.y = y
|
||||
|
||||
self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x'])
|
||||
self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
|
||||
self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
|
||||
|
||||
def test_dict_copy_order(self):
|
||||
# bpo-34320
|
||||
od = collections.OrderedDict([('a', 1), ('b', 2)])
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix a segmentation fault when using reverse iterators of empty ``dict`` objects.
|
||||
Patch by Dong-hee Na and Inada Naoki.
|
|
@ -3452,10 +3452,15 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
|
|||
di->di_dict = dict;
|
||||
di->di_used = dict->ma_used;
|
||||
di->len = dict->ma_used;
|
||||
if ((itertype == &PyDictRevIterKey_Type ||
|
||||
if (itertype == &PyDictRevIterKey_Type ||
|
||||
itertype == &PyDictRevIterItem_Type ||
|
||||
itertype == &PyDictRevIterValue_Type) && dict->ma_used) {
|
||||
itertype == &PyDictRevIterValue_Type) {
|
||||
if (dict->ma_values) {
|
||||
di->di_pos = dict->ma_used - 1;
|
||||
}
|
||||
else {
|
||||
di->di_pos = dict->ma_keys->dk_nentries - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
di->di_pos = 0;
|
||||
|
|
Loading…
Reference in New Issue