bpo-38644: Make tstate more explicit inside pystate.c (GH-19182)

Fix PyInterpreterState_New(): Don't call PyErr_SetString() when there
is no current Python thread state (if tstate is NULL).
This commit is contained in:
Victor Stinner 2020-03-26 22:46:14 +01:00 committed by GitHub
parent 728189884e
commit 71a3522ef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 47 deletions

View File

@ -1119,6 +1119,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Return the interpreter's unique ID. If there was any error in doing Return the interpreter's unique ID. If there was any error in doing
so then ``-1`` is returned and an error is set. so then ``-1`` is returned and an error is set.
The caller must hold the GIL.
.. versionadded:: 3.7 .. versionadded:: 3.7

View File

@ -527,6 +527,8 @@ since multiple such modules can be created from a single definition.
mechanisms (either by calling it directly, or by referring to its mechanisms (either by calling it directly, or by referring to its
implementation for details of the required state updates). implementation for details of the required state updates).
The caller must hold the GIL.
Return 0 on success or -1 on failure. Return 0 on success or -1 on failure.
.. versionadded:: 3.3 .. versionadded:: 3.3
@ -536,4 +538,6 @@ since multiple such modules can be created from a single definition.
Removes the module object created from *def* from the interpreter state. Removes the module object created from *def* from the interpreter state.
Return 0 on success or -1 on failure. Return 0 on success or -1 on failure.
The caller must hold the GIL.
.. versionadded:: 3.3 .. versionadded:: 3.3

View File

@ -8,6 +8,7 @@
#include "pycore_pylifecycle.h" #include "pycore_pylifecycle.h"
#include "pycore_pymem.h" #include "pycore_pymem.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "pycore_sysmodule.h"
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
CAUTION CAUTION
@ -203,7 +204,10 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
PyInterpreterState * PyInterpreterState *
PyInterpreterState_New(void) PyInterpreterState_New(void)
{ {
if (PySys_Audit("cpython.PyInterpreterState_New", NULL) < 0) { PyThreadState *tstate = _PyThreadState_GET();
/* tstate is NULL when Py_InitializeFromConfig() calls
PyInterpreterState_New() to create the main interpreter. */
if (_PySys_Audit(tstate, "cpython.PyInterpreterState_New", NULL) < 0) {
return NULL; return NULL;
} }
@ -214,6 +218,7 @@ PyInterpreterState_New(void)
interp->id_refcount = -1; interp->id_refcount = -1;
/* Don't get runtime from tstate since tstate can be NULL */
_PyRuntimeState *runtime = &_PyRuntime; _PyRuntimeState *runtime = &_PyRuntime;
interp->runtime = runtime; interp->runtime = runtime;
@ -235,8 +240,10 @@ PyInterpreterState_New(void)
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
if (interpreters->next_id < 0) { if (interpreters->next_id < 0) {
/* overflow or Py_Initialize() not called! */ /* overflow or Py_Initialize() not called! */
PyErr_SetString(PyExc_RuntimeError, if (tstate != NULL) {
"failed to get an interpreter ID"); _PyErr_SetString(tstate, PyExc_RuntimeError,
"failed to get an interpreter ID");
}
PyMem_RawFree(interp); PyMem_RawFree(interp);
interp = NULL; interp = NULL;
} }
@ -268,8 +275,11 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
{ {
_PyRuntimeState *runtime = interp->runtime; _PyRuntimeState *runtime = interp->runtime;
if (PySys_Audit("cpython.PyInterpreterState_Clear", NULL) < 0) { /* Use the current Python thread state to call audit hooks,
PyErr_Clear(); not the current Python thread state of 'interp'. */
PyThreadState *tstate = _PyThreadState_GET();
if (_PySys_Audit(tstate, "cpython.PyInterpreterState_Clear", NULL) < 0) {
_PyErr_Clear(tstate);
} }
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
@ -655,12 +665,13 @@ int
_PyState_AddModule(PyThreadState *tstate, PyObject* module, struct PyModuleDef* def) _PyState_AddModule(PyThreadState *tstate, PyObject* module, struct PyModuleDef* def)
{ {
if (!def) { if (!def) {
assert(PyErr_Occurred()); assert(_PyErr_Occurred(tstate));
return -1; return -1;
} }
if (def->m_slots) { if (def->m_slots) {
PyErr_SetString(PyExc_SystemError, _PyErr_SetString(tstate,
"PyState_AddModule called on module with slots"); PyExc_SystemError,
"PyState_AddModule called on module with slots");
return -1; return -1;
} }
@ -707,28 +718,29 @@ PyState_AddModule(PyObject* module, struct PyModuleDef* def)
int int
PyState_RemoveModule(struct PyModuleDef* def) PyState_RemoveModule(struct PyModuleDef* def)
{ {
PyInterpreterState *state; PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t index = def->m_base.m_index; PyInterpreterState *interp = tstate->interp;
if (def->m_slots) { if (def->m_slots) {
PyErr_SetString(PyExc_SystemError, _PyErr_SetString(tstate,
"PyState_RemoveModule called on module with slots"); PyExc_SystemError,
"PyState_RemoveModule called on module with slots");
return -1; return -1;
} }
state = _PyInterpreterState_GET_UNSAFE();
Py_ssize_t index = def->m_base.m_index;
if (index == 0) { if (index == 0) {
Py_FatalError("invalid module index"); Py_FatalError("invalid module index");
return -1;
} }
if (state->modules_by_index == NULL) { if (interp->modules_by_index == NULL) {
Py_FatalError("Interpreters module-list not accessible."); Py_FatalError("Interpreters module-list not accessible.");
return -1;
} }
if (index > PyList_GET_SIZE(state->modules_by_index)) { if (index > PyList_GET_SIZE(interp->modules_by_index)) {
Py_FatalError("Module index out of bounds."); Py_FatalError("Module index out of bounds.");
return -1;
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
return PyList_SetItem(state->modules_by_index, index, Py_None); return PyList_SetItem(interp->modules_by_index, index, Py_None);
} }
/* Used by PyImport_Cleanup() */ /* Used by PyImport_Cleanup() */
@ -1114,16 +1126,15 @@ PyThreadState_Next(PyThreadState *tstate) {
PyObject * PyObject *
_PyThread_CurrentFrames(void) _PyThread_CurrentFrames(void)
{ {
PyObject *result; PyThreadState *tstate = _PyThreadState_GET();
PyInterpreterState *i; if (_PySys_Audit(tstate, "sys._current_frames", NULL) < 0) {
if (PySys_Audit("sys._current_frames", NULL) < 0) {
return NULL; return NULL;
} }
result = PyDict_New(); PyObject *result = PyDict_New();
if (result == NULL) if (result == NULL) {
return NULL; return NULL;
}
/* for i in all interpreters: /* for i in all interpreters:
* for t in all of i's thread states: * for t in all of i's thread states:
@ -1131,32 +1142,35 @@ _PyThread_CurrentFrames(void)
* Because these lists can mutate even when the GIL is held, we * Because these lists can mutate even when the GIL is held, we
* need to grab head_mutex for the duration. * need to grab head_mutex for the duration.
*/ */
_PyRuntimeState *runtime = &_PyRuntime; _PyRuntimeState *runtime = tstate->interp->runtime;
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) { for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t; PyThreadState *t;
for (t = i->tstate_head; t != NULL; t = t->next) { for (t = i->tstate_head; t != NULL; t = t->next) {
PyObject *id;
int stat;
struct _frame *frame = t->frame; struct _frame *frame = t->frame;
if (frame == NULL) if (frame == NULL) {
continue; continue;
id = PyLong_FromUnsignedLong(t->thread_id); }
if (id == NULL) PyObject *id = PyLong_FromUnsignedLong(t->thread_id);
goto Fail; if (id == NULL) {
stat = PyDict_SetItem(result, id, (PyObject *)frame); goto fail;
}
int stat = PyDict_SetItem(result, id, (PyObject *)frame);
Py_DECREF(id); Py_DECREF(id);
if (stat < 0) if (stat < 0) {
goto Fail; goto fail;
}
} }
} }
goto done;
fail:
Py_CLEAR(result);
done:
HEAD_UNLOCK(runtime); HEAD_UNLOCK(runtime);
return result; return result;
Fail:
HEAD_UNLOCK(runtime);
Py_DECREF(result);
return NULL;
} }
/* Python "auto thread state" API. */ /* Python "auto thread state" API. */
@ -1436,19 +1450,19 @@ _PyObject_CheckCrossInterpreterData(PyObject *obj)
} }
static int static int
_check_xidata(_PyCrossInterpreterData *data) _check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data)
{ {
// data->data can be anything, including NULL, so we don't check it. // data->data can be anything, including NULL, so we don't check it.
// data->obj may be NULL, so we don't check it. // data->obj may be NULL, so we don't check it.
if (data->interp < 0) { if (data->interp < 0) {
PyErr_SetString(PyExc_SystemError, "missing interp"); _PyErr_SetString(tstate, PyExc_SystemError, "missing interp");
return -1; return -1;
} }
if (data->new_object == NULL) { if (data->new_object == NULL) {
PyErr_SetString(PyExc_SystemError, "missing new_object func"); _PyErr_SetString(tstate, PyExc_SystemError, "missing new_object func");
return -1; return -1;
} }
@ -1460,9 +1474,9 @@ _check_xidata(_PyCrossInterpreterData *data)
int int
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data) _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
{ {
// PyInterpreterState_Get() aborts if lookup fails, so we don't need // PyThreadState_Get() aborts if tstate is NULL.
// to check the result for NULL. PyThreadState *tstate = PyThreadState_Get();
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = tstate->interp;
// Reset data before re-populating. // Reset data before re-populating.
*data = (_PyCrossInterpreterData){0}; *data = (_PyCrossInterpreterData){0};
@ -1483,7 +1497,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
// Fill in the blanks and validate the result. // Fill in the blanks and validate the result.
data->interp = interp->id; data->interp = interp->id;
if (_check_xidata(data) != 0) { if (_check_xidata(tstate, data) != 0) {
_PyCrossInterpreterData_Release(data); _PyCrossInterpreterData_Release(data);
return -1; return -1;
} }