diff options
author | Victor Stinner <vstinner@python.org> | 2020-06-02 12:03:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-02 12:03:25 (GMT) |
commit | 59d3dce69b0a4f6ee17578ae68037cc7ae90936f (patch) | |
tree | 72eaa3932f9ff7fc0a13752a1fe706666c6e87dd /Objects/dictobject.c | |
parent | 85339f5c220a5e79c47c3a33c93f1dca5c59c52e (diff) | |
download | cpython-59d3dce69b0a4f6ee17578ae68037cc7ae90936f.zip cpython-59d3dce69b0a4f6ee17578ae68037cc7ae90936f.tar.gz cpython-59d3dce69b0a4f6ee17578ae68037cc7ae90936f.tar.bz2 |
bpo-40839: PyDict_GetItem() requires the GIL (GH-20580)
Calling PyDict_GetItem() without GIL held had been allowed for
historical reason. It is no longer allowed.
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r-- | Objects/dictobject.c | 55 |
1 files changed, 26 insertions, 29 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 809a5ed..c4d5da5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -112,7 +112,8 @@ converting the dict to the combined table. #include "Python.h" #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() -#include "pycore_object.h" +#include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_pyerrors.h" // _PyErr_Fetch() #include "pycore_pystate.h" // _PyThreadState_GET() #include "dict-common.h" #include "stringlib/eq.h" // unicode_eq() @@ -1387,14 +1388,12 @@ _PyDict_NewPresized(Py_ssize_t minused) PyObject * PyDict_GetItem(PyObject *op, PyObject *key) { - Py_hash_t hash; - Py_ssize_t ix; + if (!PyDict_Check(op)) { + return NULL; + } PyDictObject *mp = (PyDictObject *)op; - PyThreadState *tstate; - PyObject *value; - if (!PyDict_Check(op)) - return NULL; + Py_hash_t hash; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -1405,28 +1404,26 @@ PyDict_GetItem(PyObject *op, PyObject *key) } } - /* We can arrive here with a NULL tstate during initialization: try - running "python -Wi" for an example related to string interning. - Let's just hope that no exception occurs then... This must be - _PyThreadState_GET() and not PyThreadState_Get() because the latter - abort Python if tstate is NULL. */ - tstate = _PyThreadState_GET(); - if (tstate != NULL && tstate->curexc_type != NULL) { - /* preserve the existing exception */ - PyObject *err_type, *err_value, *err_tb; - PyErr_Fetch(&err_type, &err_value, &err_tb); - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); - /* ignore errors */ - PyErr_Restore(err_type, err_value, err_tb); - if (ix < 0) - return NULL; - } - else { - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); - if (ix < 0) { - PyErr_Clear(); - return NULL; - } + PyThreadState *tstate = _PyThreadState_GET(); +#ifdef Py_DEBUG + // bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem() + // with the GIL released. + _Py_EnsureTstateNotNULL(tstate); +#endif + + /* Preserve the existing exception */ + PyObject *exc_type, *exc_value, *exc_tb; + PyObject *value; + Py_ssize_t ix; + + _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); + + /* Ignore any exception raised by the lookup */ + _PyErr_Restore(tstate, exc_type, exc_value, exc_tb); + + if (ix < 0) { + return NULL; } return value; } |