mirror of
https://github.com/python/cpython.git
synced 2025-11-13 15:40:05 +00:00
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
4 changed files with 37 additions and 30 deletions
|
|
@ -100,6 +100,10 @@ Dictionary Objects
|
||||||
:meth:`__eq__` methods will get suppressed.
|
:meth:`__eq__` methods will get suppressed.
|
||||||
To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
|
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)
|
.. 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).
|
see :c:func:`Py_SET_SIZE()` (available since Python 3.9).
|
||||||
(Contributed by Victor Stinner in :issue:`39573`.)
|
(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
|
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 "Python.h"
|
||||||
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
|
#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 "pycore_pystate.h" // _PyThreadState_GET()
|
||||||
#include "dict-common.h"
|
#include "dict-common.h"
|
||||||
#include "stringlib/eq.h" // unicode_eq()
|
#include "stringlib/eq.h" // unicode_eq()
|
||||||
|
|
@ -1387,14 +1388,12 @@ _PyDict_NewPresized(Py_ssize_t minused)
|
||||||
PyObject *
|
PyObject *
|
||||||
PyDict_GetItem(PyObject *op, PyObject *key)
|
PyDict_GetItem(PyObject *op, PyObject *key)
|
||||||
{
|
{
|
||||||
Py_hash_t hash;
|
if (!PyDict_Check(op)) {
|
||||||
Py_ssize_t ix;
|
|
||||||
PyDictObject *mp = (PyDictObject *)op;
|
|
||||||
PyThreadState *tstate;
|
|
||||||
PyObject *value;
|
|
||||||
|
|
||||||
if (!PyDict_Check(op))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
PyDictObject *mp = (PyDictObject *)op;
|
||||||
|
|
||||||
|
Py_hash_t hash;
|
||||||
if (!PyUnicode_CheckExact(key) ||
|
if (!PyUnicode_CheckExact(key) ||
|
||||||
(hash = ((PyASCIIObject *) key)->hash) == -1)
|
(hash = ((PyASCIIObject *) key)->hash) == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -1405,29 +1404,27 @@ PyDict_GetItem(PyObject *op, PyObject *key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can arrive here with a NULL tstate during initialization: try
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
running "python -Wi" for an example related to string interning.
|
#ifdef Py_DEBUG
|
||||||
Let's just hope that no exception occurs then... This must be
|
// bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem()
|
||||||
_PyThreadState_GET() and not PyThreadState_Get() because the latter
|
// with the GIL released.
|
||||||
abort Python if tstate is NULL. */
|
_Py_EnsureTstateNotNULL(tstate);
|
||||||
tstate = _PyThreadState_GET();
|
#endif
|
||||||
if (tstate != NULL && tstate->curexc_type != NULL) {
|
|
||||||
/* preserve the existing exception */
|
/* Preserve the existing exception */
|
||||||
PyObject *err_type, *err_value, *err_tb;
|
PyObject *exc_type, *exc_value, *exc_tb;
|
||||||
PyErr_Fetch(&err_type, &err_value, &err_tb);
|
PyObject *value;
|
||||||
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
|
Py_ssize_t ix;
|
||||||
/* ignore errors */
|
|
||||||
PyErr_Restore(err_type, err_value, err_tb);
|
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
||||||
if (ix < 0)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
|
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) {
|
if (ix < 0) {
|
||||||
PyErr_Clear();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue