summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-01-12 17:12:21 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2017-01-12 17:12:21 (GMT)
commit42e1ea9a10aa6c3df40af3b7561d6251c8e2ac9c (patch)
treed54140f730a38805fa55a7a5cc90b0e894d91318 /Objects
parent12c4aba1a0fbd934a66d6b97c29c36d7de14e755 (diff)
parent67796521dd22b3008788a75108b45f33d06f85dd (diff)
downloadcpython-42e1ea9a10aa6c3df40af3b7561d6251c8e2ac9c.zip
cpython-42e1ea9a10aa6c3df40af3b7561d6251c8e2ac9c.tar.gz
cpython-42e1ea9a10aa6c3df40af3b7561d6251c8e2ac9c.tar.bz2
Issue #28969: Fixed race condition in C implementation of functools.lru_cache.
KeyError could be raised when cached function with full cache was simultaneously called from differen threads with the same uncached arguments.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6494193..a7b403b 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1829,9 +1829,8 @@ PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
/* Internal version of dict.pop(). */
PyObject *
-_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
+_PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *deflt)
{
- Py_hash_t hash;
Py_ssize_t ix, hashpos;
PyObject *old_value, *old_key;
PyDictKeyEntry *ep;
@@ -1849,12 +1848,6 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
_PyErr_SetKeyError(key);
return NULL;
}
- if (!PyUnicode_CheckExact(key) ||
- (hash = ((PyASCIIObject *) key)->hash) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
if (ix == DKIX_ERROR)
return NULL;
@@ -1892,6 +1885,28 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
return old_value;
}
+PyObject *
+_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
+{
+ Py_hash_t hash;
+
+ if (((PyDictObject *)dict)->ma_used == 0) {
+ if (deflt) {
+ Py_INCREF(deflt);
+ return deflt;
+ }
+ _PyErr_SetKeyError(key);
+ return NULL;
+ }
+ if (!PyUnicode_CheckExact(key) ||
+ (hash = ((PyASCIIObject *) key)->hash) == -1) {
+ hash = PyObject_Hash(key);
+ if (hash == -1)
+ return NULL;
+ }
+ return _PyDict_Pop_KnownHash(dict, key, hash, deflt);
+}
+
/* Internal version of dict.from_keys(). It is subclass-friendly. */
PyObject *
_PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)