Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 59d3dce

Browse files
authored
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.
1 parent 85339f5 commit 59d3dce

4 files changed

Lines changed: 36 additions & 29 deletions

File tree

Doc/c-api/dict.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ Dictionary Objects
100100
:meth:`__eq__` methods will get suppressed.
101101
To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
102102
103+
.. versionchanged:: 3.10
104+
Calling this API without :term:`GIL` held had been allowed for historical
105+
reason. It is no longer allowed.
106+
103107
104108
.. c:function:: PyObject* PyDict_GetItemWithError(PyObject *p, PyObject *key)
105109

Doc/whatsnew/3.10.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,9 @@ Porting to Python 3.10
148148
see :c:func:`Py_SET_SIZE()` (available since Python 3.9).
149149
(Contributed by Victor Stinner in :issue:`39573`.)
150150

151+
* Calling :c:func:`PyDict_GetItem` without :term:`GIL` held had been allowed
152+
for historical reason. It is no longer allowed.
153+
(Contributed by Victor Stinner in :issue:`40839`.)
154+
151155
Removed
152156
-------
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Calling :c:func:`PyDict_GetItem` without :term:`GIL` held had been allowed for
2+
historical reason. It is no longer allowed.

Objects/dictobject.c

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ converting the dict to the combined table.
112112

113113
#include "Python.h"
114114
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
115-
#include "pycore_object.h"
115+
#include "pycore_object.h" // _PyObject_GC_TRACK()
116+
#include "pycore_pyerrors.h" // _PyErr_Fetch()
116117
#include "pycore_pystate.h" // _PyThreadState_GET()
117118
#include "dict-common.h"
118119
#include "stringlib/eq.h" // unicode_eq()
@@ -1387,14 +1388,12 @@ _PyDict_NewPresized(Py_ssize_t minused)
13871388
PyObject *
13881389
PyDict_GetItem(PyObject *op, PyObject *key)
13891390
{
1390-
Py_hash_t hash;
1391-
Py_ssize_t ix;
1391+
if (!PyDict_Check(op)) {
1392+
return NULL;
1393+
}
13921394
PyDictObject *mp = (PyDictObject *)op;
1393-
PyThreadState *tstate;
1394-
PyObject *value;
13951395

1396-
if (!PyDict_Check(op))
1397-
return NULL;
1396+
Py_hash_t hash;
13981397
if (!PyUnicode_CheckExact(key) ||
13991398
(hash = ((PyASCIIObject *) key)->hash) == -1)
14001399
{
@@ -1405,28 +1404,26 @@ PyDict_GetItem(PyObject *op, PyObject *key)
14051404
}
14061405
}
14071406

1408-
/* We can arrive here with a NULL tstate during initialization: try
1409-
running "python -Wi" for an example related to string interning.
1410-
Let's just hope that no exception occurs then... This must be
1411-
_PyThreadState_GET() and not PyThreadState_Get() because the latter
1412-
abort Python if tstate is NULL. */
1413-
tstate = _PyThreadState_GET();
1414-
if (tstate != NULL && tstate->curexc_type != NULL) {
1415-
/* preserve the existing exception */
1416-
PyObject *err_type, *err_value, *err_tb;
1417-
PyErr_Fetch(&err_type, &err_value, &err_tb);
1418-
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
1419-
/* ignore errors */
1420-
PyErr_Restore(err_type, err_value, err_tb);
1421-
if (ix < 0)
1422-
return NULL;
1423-
}
1424-
else {
1425-
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
1426-
if (ix < 0) {
1427-
PyErr_Clear();
1428-
return NULL;
1429-
}
1407+
PyThreadState *tstate = _PyThreadState_GET();
1408+
#ifdef Py_DEBUG
1409+
// bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem()
1410+
// with the GIL released.
1411+
_Py_EnsureTstateNotNULL(tstate);
1412+
#endif
1413+
1414+
/* Preserve the existing exception */
1415+
PyObject *exc_type, *exc_value, *exc_tb;
1416+
PyObject *value;
1417+
Py_ssize_t ix;
1418+
1419+
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
1420+
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
1421+
1422+
/* Ignore any exception raised by the lookup */
1423+
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
1424+
1425+
if (ix < 0) {
1426+
return NULL;
14301427
}
14311428
return value;
14321429
}

0 commit comments

Comments
 (0)