[Python-checkins] bpo-40839: PyDict_GetItem() requires the GIL (GH-20580)
Victor Stinner
webhook-mailer at python.org
Tue Jun 2 08:03:34 EDT 2020
https://github.com/python/cpython/commit/59d3dce69b0a4f6ee17578ae68037cc7ae90936f
commit: 59d3dce69b0a4f6ee17578ae68037cc7ae90936f
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-06-02T14:03:25+02:00
summary:
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.
files:
A Misc/NEWS.d/next/C API/2020-06-01-20-47-49.bpo-40839.bAi52Z.rst
M Doc/c-api/dict.rst
M Doc/whatsnew/3.10.rst
M Objects/dictobject.c
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index 2fb29cdd61778..7493837ac622f 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -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)
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 95c5aa7ec6e6b..0b656475b7167 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -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
-------
diff --git a/Misc/NEWS.d/next/C API/2020-06-01-20-47-49.bpo-40839.bAi52Z.rst b/Misc/NEWS.d/next/C API/2020-06-01-20-47-49.bpo-40839.bAi52Z.rst
new file mode 100644
index 0000000000000..5de2f40c14eca
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-06-01-20-47-49.bpo-40839.bAi52Z.rst
@@ -0,0 +1,2 @@
+Calling :c:func:`PyDict_GetItem` without :term:`GIL` held had been allowed for
+historical reason. It is no longer allowed.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 809a5ed778737..c4d5da51f3193 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;
}
More information about the Python-checkins
mailing list