bpo-36710: Add tstate parameter in ceval.c (GH-13547)

* Fix a possible reference leak in _PyErr_Print() if exception
  is NULL.
* PyErr_BadInternalCall(): replace PyErr_Format() with _PyErr_SetString().
* Add pycore_pyerrors.h header file.
* New functions:

  * _PyErr_Clear()
  * _PyErr_Fetch()
  * _PyErr_Print()
  * _PyErr_Restore()
  * _PyErr_SetObject()
  * _PyErr_SetString()

* Add 'tstate' parameter to _PyEval_AddPendingCall().
This commit is contained in:
Victor Stinner 2019-05-24 17:01:38 +02:00 committed by GitHub
parent 13d4e6a4a0
commit 438a12dd9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 563 additions and 403 deletions

View File

@ -19,6 +19,7 @@ PyAPI_FUNC(void) _PyEval_FiniThreads(
PyAPI_FUNC(void) _PyEval_SignalReceived(
struct _ceval_runtime_state *ceval);
PyAPI_FUNC(int) _PyEval_AddPendingCall(
PyThreadState *tstate,
struct _ceval_runtime_state *ceval,
int (*func)(void *),
void *arg);

View File

@ -0,0 +1,62 @@
#ifndef Py_INTERNAL_PYERRORS_H
#define Py_INTERNAL_PYERRORS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif
static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
{
return tstate == NULL ? NULL : tstate->curexc_type;
}
PyAPI_FUNC(void) _PyErr_Fetch(
PyThreadState *tstate,
PyObject **type,
PyObject **value,
PyObject **traceback);
PyAPI_FUNC(int) _PyErr_ExceptionMatches(
PyThreadState *tstate,
PyObject *exc);
PyAPI_FUNC(void) _PyErr_Restore(
PyThreadState *tstate,
PyObject *type,
PyObject *value,
PyObject *traceback);
PyAPI_FUNC(void) _PyErr_SetObject(
PyThreadState *tstate,
PyObject *type,
PyObject *value);
PyAPI_FUNC(void) _PyErr_Clear(PyThreadState *tstate);
PyAPI_FUNC(void) _PyErr_SetNone(PyThreadState *tstate, PyObject *exception);
PyAPI_FUNC(void) _PyErr_SetString(
PyThreadState *tstate,
PyObject *exception,
const char *string);
PyAPI_FUNC(PyObject *) _PyErr_Format(
PyThreadState *tstate,
PyObject *exception,
const char *format,
...);
PyAPI_FUNC(void) _PyErr_NormalizeException(
PyThreadState *tstate,
PyObject **exc,
PyObject **val,
PyObject **tb);
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_PYERRORS_H */

View File

@ -106,6 +106,8 @@ PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p);
PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable);
PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
#ifndef Py_INTERNAL_MEM_H
#define Py_INTERNAL_MEM_H
#ifndef Py_INTERNAL_PYMEM_H
#define Py_INTERNAL_PYMEM_H
#ifdef __cplusplus
extern "C" {
#endif
@ -191,4 +191,4 @@ PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_MEM_H */
#endif /* !Py_INTERNAL_PYMEM_H */

View File

@ -1077,6 +1077,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_hamt.h \
$(srcdir)/Include/internal/pycore_object.h \
$(srcdir)/Include/internal/pycore_pathconfig.h \
$(srcdir)/Include/internal/pycore_pyerrors.h \
$(srcdir)/Include/internal/pycore_pyhash.h \
$(srcdir)/Include/internal/pycore_pylifecycle.h \
$(srcdir)/Include/internal/pycore_pymem.h \

View File

@ -258,6 +258,7 @@ trip_signal(int sig_num)
/* Notify ceval.c */
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
_PyEval_SignalReceived(&runtime->ceval);
/* And then write to the wakeup fd *after* setting all the globals and
@ -298,7 +299,7 @@ trip_signal(int sig_num)
{
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
_PyEval_AddPendingCall(&runtime->ceval,
_PyEval_AddPendingCall(tstate, &runtime->ceval,
report_wakeup_send_error,
(void *)(intptr_t) last_error);
}
@ -317,7 +318,7 @@ trip_signal(int sig_num)
{
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
_PyEval_AddPendingCall(&runtime->ceval,
_PyEval_AddPendingCall(tstate, &runtime->ceval,
report_wakeup_write_error,
(void *)(intptr_t)errno);
}

View File

@ -168,6 +168,7 @@
<ClInclude Include="..\Include\internal\pycore_hamt.h" />
<ClInclude Include="..\Include\internal\pycore_object.h" />
<ClInclude Include="..\Include\internal\pycore_pathconfig.h" />
<ClInclude Include="..\Include\internal\pycore_pyerrors.h" />
<ClInclude Include="..\Include\internal\pycore_pyhash.h" />
<ClInclude Include="..\Include\internal\pycore_pylifecycle.h" />
<ClInclude Include="..\Include\internal\pycore_pymem.h" />

View File

@ -207,6 +207,9 @@
<ClInclude Include="..\Include\internal\pycore_pathconfig.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_pyerrors.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_pyhash.h">
<Filter>Include</Filter>
</ClInclude>

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
#include "Python.h"
#include "pycore_coreconfig.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h"
#include "pycore_traceback.h"
@ -27,13 +28,13 @@ _Py_IDENTIFIER(builtins);
_Py_IDENTIFIER(stderr);
/* Forward declaration */
static void _PyErr_Fetch(PyThreadState *tstate, PyObject **p_type,
PyObject **p_value, PyObject **p_traceback);
static void _PyErr_Clear(PyThreadState *tstate);
/* Forward declarations */
static PyObject *
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
const char *format, va_list vargs);
static void
void
_PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value,
PyObject *traceback)
{
@ -95,7 +96,7 @@ _PyErr_CreateException(PyObject *exception, PyObject *value)
}
}
static void
void
_PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
{
PyObject *exc_value;
@ -103,7 +104,7 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
if (exception != NULL &&
!PyExceptionClass_Check(exception)) {
PyErr_Format(PyExc_SystemError,
_PyErr_Format(tstate, PyExc_SystemError,
"exception %R not a BaseException subclass",
exception);
return;
@ -181,7 +182,7 @@ _PyErr_SetKeyError(PyObject *arg)
Py_DECREF(tup);
}
static void
void
_PyErr_SetNone(PyThreadState *tstate, PyObject *exception)
{
_PyErr_SetObject(tstate, exception, (PyObject *)NULL);
@ -196,7 +197,7 @@ PyErr_SetNone(PyObject *exception)
}
static void
void
_PyErr_SetString(PyThreadState *tstate, PyObject *exception,
const char *string)
{
@ -213,13 +214,6 @@ PyErr_SetString(PyObject *exception, const char *string)
}
static PyObject*
_PyErr_Occurred(PyThreadState *tstate)
{
return tstate == NULL ? NULL : tstate->curexc_type;
}
PyObject* _Py_HOT_FUNCTION
PyErr_Occurred(void)
{
@ -260,11 +254,18 @@ PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
}
int
_PyErr_ExceptionMatches(PyThreadState *tstate, PyObject *exc)
{
return PyErr_GivenExceptionMatches(_PyErr_Occurred(tstate), exc);
}
int
PyErr_ExceptionMatches(PyObject *exc)
{
PyThreadState *tstate = _PyThreadState_GET();
return PyErr_GivenExceptionMatches(_PyErr_Occurred(tstate), exc);
return _PyErr_ExceptionMatches(tstate, exc);
}
@ -278,7 +279,7 @@ PyErr_ExceptionMatches(PyObject *exc)
XXX: should PyErr_NormalizeException() also call
PyException_SetTraceback() with the resulting value and tb?
*/
static void
void
_PyErr_NormalizeException(PyThreadState *tstate, PyObject **exc,
PyObject **val, PyObject **tb)
{
@ -390,7 +391,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
}
static void
void
_PyErr_Fetch(PyThreadState *tstate, PyObject **p_type, PyObject **p_value,
PyObject **p_traceback)
{
@ -412,7 +413,7 @@ PyErr_Fetch(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
}
static void
void
_PyErr_Clear(PyThreadState *tstate)
{
_PyErr_Restore(tstate, NULL, NULL, NULL);
@ -506,7 +507,7 @@ _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
Py_DECREF(exc);
assert(!_PyErr_Occurred(tstate));
PyErr_FormatV(exception, format, vargs);
_PyErr_FormatV(tstate, exception, format, vargs);
_PyErr_Fetch(tstate, &exc, &val2, &tb);
_PyErr_NormalizeException(tstate, &exc, &val2, &tb);
@ -895,7 +896,8 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
void
_PyErr_BadInternalCall(const char *filename, int lineno)
{
PyErr_Format(PyExc_SystemError,
PyThreadState *tstate = _PyThreadState_GET();
_PyErr_Format(tstate, PyExc_SystemError,
"%s:%d: bad argument to internal function",
filename, lineno);
}
@ -907,16 +909,17 @@ void
PyErr_BadInternalCall(void)
{
assert(0 && "bad argument to internal function");
PyErr_Format(PyExc_SystemError,
PyThreadState *tstate = _PyThreadState_GET();
_PyErr_SetString(tstate, PyExc_SystemError,
"bad argument to internal function");
}
#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__)
PyObject *
PyErr_FormatV(PyObject *exception, const char *format, va_list vargs)
static PyObject *
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
const char *format, va_list vargs)
{
PyThreadState *tstate = _PyThreadState_GET();
PyObject* string;
/* Issue #23571: PyUnicode_FromFormatV() must not be called with an
@ -932,7 +935,16 @@ PyErr_FormatV(PyObject *exception, const char *format, va_list vargs)
PyObject *
PyErr_Format(PyObject *exception, const char *format, ...)
PyErr_FormatV(PyObject *exception, const char *format, va_list vargs)
{
PyThreadState *tstate = _PyThreadState_GET();
return _PyErr_FormatV(tstate, exception, format, vargs);
}
PyObject *
_PyErr_Format(PyThreadState *tstate, PyObject *exception,
const char *format, ...)
{
va_list vargs;
#ifdef HAVE_STDARG_PROTOTYPES
@ -940,7 +952,23 @@ PyErr_Format(PyObject *exception, const char *format, ...)
#else
va_start(vargs);
#endif
PyErr_FormatV(exception, format, vargs);
_PyErr_FormatV(tstate, exception, format, vargs);
va_end(vargs);
return NULL;
}
PyObject *
PyErr_Format(PyObject *exception, const char *format, ...)
{
PyThreadState *tstate = _PyThreadState_GET();
va_list vargs;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, format);
#else
va_start(vargs);
#endif
_PyErr_FormatV(tstate, exception, format, vargs);
va_end(vargs);
return NULL;
}

View File

@ -12,6 +12,7 @@
#include "Python-ast.h"
#undef Yield /* undefine macro conflicting with <winbase.h> */
#include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
#include "pycore_pystate.h"
#include "grammar.h"
@ -542,12 +543,6 @@ finally:
return 0;
}
void
PyErr_Print(void)
{
PyErr_PrintEx(1);
}
static void
print_error_text(PyObject *f, int offset, PyObject *text_obj)
{
@ -667,34 +662,38 @@ handle_system_exit(void)
}
void
PyErr_PrintEx(int set_sys_last_vars)
static void
_PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars)
{
PyObject *exception, *v, *tb, *hook;
handle_system_exit();
PyErr_Fetch(&exception, &v, &tb);
if (exception == NULL)
return;
PyErr_NormalizeException(&exception, &v, &tb);
_PyErr_Fetch(tstate, &exception, &v, &tb);
if (exception == NULL) {
goto done;
}
_PyErr_NormalizeException(tstate, &exception, &v, &tb);
if (tb == NULL) {
tb = Py_None;
Py_INCREF(tb);
}
PyException_SetTraceback(v, tb);
if (exception == NULL)
return;
if (exception == NULL) {
goto done;
}
/* Now we know v != NULL too */
if (set_sys_last_vars) {
if (_PySys_SetObjectId(&PyId_last_type, exception) < 0) {
PyErr_Clear();
_PyErr_Clear(tstate);
}
if (_PySys_SetObjectId(&PyId_last_value, v) < 0) {
PyErr_Clear();
_PyErr_Clear(tstate);
}
if (_PySys_SetObjectId(&PyId_last_traceback, tb) < 0) {
PyErr_Clear();
_PyErr_Clear(tstate);
}
}
hook = _PySys_GetObjectId(&PyId_excepthook);
@ -710,8 +709,8 @@ PyErr_PrintEx(int set_sys_last_vars)
handle_system_exit();
PyObject *exception2, *v2, *tb2;
PyErr_Fetch(&exception2, &v2, &tb2);
PyErr_NormalizeException(&exception2, &v2, &tb2);
_PyErr_Fetch(tstate, &exception2, &v2, &tb2);
_PyErr_NormalizeException(tstate, &exception2, &v2, &tb2);
/* It should not be possible for exception2 or v2
to be NULL. However PyErr_Display() can't
tolerate NULLs, so just be safe. */
@ -733,15 +732,37 @@ PyErr_PrintEx(int set_sys_last_vars)
Py_XDECREF(tb2);
}
Py_XDECREF(result);
} else {
}
else {
PySys_WriteStderr("sys.excepthook is missing\n");
PyErr_Display(exception, v, tb);
}
done:
Py_XDECREF(exception);
Py_XDECREF(v);
Py_XDECREF(tb);
}
void
_PyErr_Print(PyThreadState *tstate)
{
_PyErr_PrintEx(tstate, 1);
}
void
PyErr_PrintEx(int set_sys_last_vars)
{
PyThreadState *tstate = _PyThreadState_GET();
_PyErr_PrintEx(tstate, set_sys_last_vars);
}
void
PyErr_Print(void)
{
PyErr_PrintEx(1);
}
static void
print_exception(PyObject *f, PyObject *value)
{