mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
85339f5c22
commit
59d3dce69b
|
@ -100,6 +100,10 @@ Dictionary Objects
|
|||
:meth:`__eq__` methods will get suppressed.
|
||||
To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
Calling this API without :term:`GIL` held had been allowed for historical
|
||||
reason. It is no longer allowed.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_GetItemWithError(PyObject *p, PyObject *key)
|
||||
|
||||
|
|
|
@ -148,5 +148,9 @@ Porting to Python 3.10
|
|||
see :c:func:`Py_SET_SIZE()` (available since Python 3.9).
|
||||
(Contributed by Victor Stinner in :issue:`39573`.)
|
||||
|
||||
* Calling :c:func:`PyDict_GetItem` without :term:`GIL` held had been allowed
|
||||
for historical reason. It is no longer allowed.
|
||||
(Contributed by Victor Stinner in :issue:`40839`.)
|
||||
|
||||
Removed
|
||||
-------
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Calling :c:func:`PyDict_GetItem` without :term:`GIL` held had been allowed for
|
||||
historical reason. It is no longer allowed.
|
|
@ -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;
|
||||
PyDictObject *mp = (PyDictObject *)op;
|
||||
PyThreadState *tstate;
|
||||
PyObject *value;
|
||||
|
||||
if (!PyDict_Check(op))
|
||||
if (!PyDict_Check(op)) {
|
||||
return NULL;
|
||||
}
|
||||
PyDictObject *mp = (PyDictObject *)op;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue