mirror of https://github.com/python/cpython
Issue #24347: Set KeyError if PyDict_GetItemWithError returns NULL.
This commit is contained in:
parent
fa1b47cc5a
commit
a762af74b2
|
@ -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) \
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -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?
|
||||||
==================================
|
==================================
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
Loading…
Reference in New Issue