Issue #25406: Fixed a bug in C implementation of OrderedDict.move_to_end()

that caused segmentation fault or hang in iterating after moving several
items to the start of ordered dict.
This commit is contained in:
Serhiy Storchaka 2015-10-14 19:21:24 +03:00
parent c1e98de7be
commit 992ec46acc
3 changed files with 28 additions and 21 deletions

View File

@ -1995,6 +1995,20 @@ class OrderedDictTests:
with self.assertRaises(KeyError): with self.assertRaises(KeyError):
od.move_to_end('x', 0) od.move_to_end('x', 0)
def test_move_to_end_issue25406(self):
OrderedDict = self.module.OrderedDict
od = OrderedDict.fromkeys('abc')
od.move_to_end('c', last=False)
self.assertEqual(list(od), list('cab'))
od.move_to_end('a', last=False)
self.assertEqual(list(od), list('acb'))
od = OrderedDict.fromkeys('abc')
od.move_to_end('a')
self.assertEqual(list(od), list('bca'))
od.move_to_end('c')
self.assertEqual(list(od), list('bac'))
def test_sizeof(self): def test_sizeof(self):
OrderedDict = self.module.OrderedDict OrderedDict = self.module.OrderedDict
# Wimpy test: Just verify the reported size is larger than a regular dict # Wimpy test: Just verify the reported size is larger than a regular dict

View File

@ -45,6 +45,10 @@ Core and Builtins
Library Library
------- -------
- Issue #25406: Fixed a bug in C implementation of OrderedDict.move_to_end()
that caused segmentation fault or hang in iterating after moving several
items to the start of ordered dict.
- Issue #25364: zipfile now works in threads disabled builds. - Issue #25364: zipfile now works in threads disabled builds.
- Issue #25328: smtpd's SMTPChannel now correctly raises a ValueError if both - Issue #25328: smtpd's SMTPChannel now correctly raises a ValueError if both

View File

@ -618,37 +618,26 @@ _odict_find_node(PyODictObject *od, PyObject *key)
static void static void
_odict_add_head(PyODictObject *od, _ODictNode *node) _odict_add_head(PyODictObject *od, _ODictNode *node)
{ {
if (_odict_FIRST(od) == NULL) { _odictnode_PREV(node) = NULL;
_odictnode_PREV(node) = NULL; _odictnode_NEXT(node) = _odict_FIRST(od);
_odictnode_NEXT(node) = NULL; if (_odict_FIRST(od) == NULL)
_odict_FIRST(od) = node;
_odict_LAST(od) = node; _odict_LAST(od) = node;
} else
else {
_odictnode_PREV(node) = NULL;
_odictnode_NEXT(node) = _odict_FIRST(od);
_odict_FIRST(od) = node;
_odictnode_PREV(_odict_FIRST(od)) = node; _odictnode_PREV(_odict_FIRST(od)) = node;
} _odict_FIRST(od) = node;
od->od_state++; od->od_state++;
} }
static void static void
_odict_add_tail(PyODictObject *od, _ODictNode *node) _odict_add_tail(PyODictObject *od, _ODictNode *node)
{ {
if (_odict_LAST(od) == NULL) { _odictnode_PREV(node) = _odict_LAST(od);
_odictnode_PREV(node) = NULL; _odictnode_NEXT(node) = NULL;
_odictnode_NEXT(node) = NULL; if (_odict_LAST(od) == NULL)
_odict_FIRST(od) = node; _odict_FIRST(od) = node;
_odict_LAST(od) = node; else
}
else {
_odictnode_PREV(node) = _odict_LAST(od);
_odictnode_NEXT(node) = NULL;
_odictnode_NEXT(_odict_LAST(od)) = node; _odictnode_NEXT(_odict_LAST(od)) = node;
_odict_LAST(od) = node; _odict_LAST(od) = node;
}
od->od_state++; od->od_state++;
} }