Issue #24347: Set KeyError if PyDict_GetItemWithError returns NULL.

This commit is contained in:
Eric Snow 2015-06-01 22:59:08 -06:00
parent fa1b47cc5a
commit a762af74b2
4 changed files with 69 additions and 15 deletions

View File

@ -30,6 +30,8 @@ PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key);
/* wrappers around PyDict* functions */ /* wrappers around PyDict* functions */
#define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key) #define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key)
#define PyODict_GetItemWithError(od, key) \
PyDict_GetItemWithError((PyObject *)od, key)
#define PyODict_Contains(od, key) PyDict_Contains((PyObject *)od, key) #define PyODict_Contains(od, key) PyDict_Contains((PyObject *)od, key)
#define PyODict_Size(od) PyDict_Size((PyObject *)od) #define PyODict_Size(od) PyDict_Size((PyObject *)od)
#define PyODict_GetItemString(od, key) \ #define PyODict_GetItemString(od, key) \

View File

@ -2037,6 +2037,24 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
del od[colliding] del od[colliding]
self.assertEqual(list(od.items()), [(key, ...), ('after', ...)]) self.assertEqual(list(od.items()), [(key, ...), ('after', ...)])
def test_issue24347(self):
OrderedDict = self.module.OrderedDict
class Key:
def __hash__(self):
return randrange(100000)
od = OrderedDict()
for i in range(100):
key = Key()
od[key] = i
# These should not crash.
with self.assertRaises(KeyError):
repr(od)
with self.assertRaises(KeyError):
od.copy()
class PurePythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol): class PurePythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol):

View File

@ -15,6 +15,8 @@ Core and Builtins
Library Library
------- -------
- Issue #24347: Set KeyError if PyDict_GetItemWithError returns NULL.
What's New in Python 3.5.0 beta 2? What's New in Python 3.5.0 beta 2?
================================== ==================================

View File

@ -511,7 +511,7 @@ struct _odictnode {
(node->key) (node->key)
/* borrowed reference */ /* borrowed reference */
#define _odictnode_VALUE(node, od) \ #define _odictnode_VALUE(node, od) \
PyODict_GetItem((PyObject *)od, _odictnode_KEY(node)) PyODict_GetItemWithError((PyObject *)od, _odictnode_KEY(node))
/* If needed we could also have _odictnode_HASH. */ /* If needed we could also have _odictnode_HASH. */
#define _odictnode_PREV(node) (node->prev) #define _odictnode_PREV(node) (node->prev)
#define _odictnode_NEXT(node) (node->next) #define _odictnode_NEXT(node) (node->next)
@ -1313,10 +1313,14 @@ odict_copy(register PyODictObject *od)
if (PyODict_CheckExact(od)) { if (PyODict_CheckExact(od)) {
_odict_FOREACH(od, node) { _odict_FOREACH(od, node) {
int res = PyODict_SetItem((PyObject *)od_copy, PyObject *key = _odictnode_KEY(node);
_odictnode_KEY(node), PyObject *value = _odictnode_VALUE(node, od);
_odictnode_VALUE(node, od)); if (value == NULL) {
if (res != 0) if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
goto fail;
}
if (PyODict_SetItem((PyObject *)od_copy, key, value) != 0)
goto fail; goto fail;
} }
} }
@ -1538,7 +1542,6 @@ odict_repr(PyODictObject *self)
Py_ssize_t count = -1; Py_ssize_t count = -1;
PyObject *pieces = NULL, *result = NULL, *cls = NULL; PyObject *pieces = NULL, *result = NULL, *cls = NULL;
PyObject *classname = NULL, *format = NULL, *args = NULL; PyObject *classname = NULL, *format = NULL, *args = NULL;
_ODictNode *node;
i = Py_ReprEnter((PyObject *)self); i = Py_ReprEnter((PyObject *)self);
if (i != 0) { if (i != 0) {
@ -1551,13 +1554,21 @@ odict_repr(PyODictObject *self)
} }
if (PyODict_CheckExact(self)) { if (PyODict_CheckExact(self)) {
_ODictNode *node;
pieces = PyList_New(PyODict_SIZE(self)); pieces = PyList_New(PyODict_SIZE(self));
if (pieces == NULL) if (pieces == NULL)
goto Done; goto Done;
_odict_FOREACH(self, node) { _odict_FOREACH(self, node) {
PyObject *pair = PyTuple_Pack(2, _odictnode_KEY(node), PyObject *pair;
_odictnode_VALUE(node, self)); PyObject *key = _odictnode_KEY(node);
PyObject *value = _odictnode_VALUE(node, self);
if (value == NULL) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
pair = PyTuple_Pack(2, key, value);
if (pair == NULL) if (pair == NULL)
goto Done; goto Done;
@ -1813,7 +1824,7 @@ static void
odictiter_dealloc(odictiterobject *di) odictiter_dealloc(odictiterobject *di)
{ {
_PyObject_GC_UNTRACK(di); _PyObject_GC_UNTRACK(di);
Py_DECREF(di->di_odict); Py_XDECREF(di->di_odict);
Py_XDECREF(di->di_current); Py_XDECREF(di->di_current);
if (di->kind & (_odict_ITER_KEYS | _odict_ITER_VALUES)) { if (di->kind & (_odict_ITER_KEYS | _odict_ITER_VALUES)) {
Py_DECREF(di->di_result); Py_DECREF(di->di_result);
@ -1830,16 +1841,21 @@ odictiter_traverse(odictiterobject *di, visitproc visit, void *arg)
return 0; return 0;
} }
/* In order to protect against modifications during iteration, we track
* the current key instead of the current node. */
static PyObject * static PyObject *
odictiter_nextkey(odictiterobject *di) odictiter_nextkey(odictiterobject *di)
{ {
PyObject *key; PyObject *key = NULL;
_ODictNode *node; _ODictNode *node;
int reversed = di->kind & _odict_ITER_REVERSED; int reversed = di->kind & _odict_ITER_REVERSED;
/* Get the key. */ if (di->di_odict == NULL)
if (di->di_current == NULL)
return NULL; return NULL;
if (di->di_current == NULL)
goto done; /* We're already done. */
/* Get the key. */
node = _odict_find_node(di->di_odict, di->di_current); node = _odict_find_node(di->di_odict, di->di_current);
if (node == NULL) { if (node == NULL) {
/* Must have been deleted. */ /* Must have been deleted. */
@ -1860,6 +1876,10 @@ odictiter_nextkey(odictiterobject *di)
} }
return key; return key;
done:
Py_CLEAR(di->di_odict);
return key;
} }
static PyObject * static PyObject *
@ -1882,8 +1902,10 @@ odictiter_iternext(odictiterobject *di)
value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */ value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */
if (value == NULL) { if (value == NULL) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
Py_DECREF(key); Py_DECREF(key);
return NULL; goto done;
} }
Py_INCREF(value); Py_INCREF(value);
@ -1899,7 +1921,7 @@ odictiter_iternext(odictiterobject *di)
if (result == NULL) { if (result == NULL) {
Py_DECREF(key); Py_DECREF(key);
Py_DECREF(value); Py_DECREF(value);
return NULL; goto done;
} }
} }
@ -1911,10 +1933,20 @@ odictiter_iternext(odictiterobject *di)
/* Handle the values case. */ /* Handle the values case. */
else { else {
value = PyODict_GetItem((PyObject *)di->di_odict, key); value = PyODict_GetItem((PyObject *)di->di_odict, key);
Py_XINCREF(value);
Py_DECREF(key); Py_DECREF(key);
if (value == NULL) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
goto done;
}
Py_INCREF(value);
return value; return value;
} }
done:
Py_CLEAR(di->di_current);
Py_CLEAR(di->di_odict);
return NULL;
} }
/* No need for tp_clear because odictiterobject is not mutable. */ /* No need for tp_clear because odictiterobject is not mutable. */