Browse Source
bpo-36829: PyErr_WriteUnraisable() normalizes exception (GH-13507)
PyErr_WriteUnraisable() now creates a traceback object if there is no
current traceback. Moreover, call PyErr_NormalizeException() and
PyException_SetTraceback() to normalize the exception value. Ignore
silently any error.
pull/13518/head
Victor Stinner
7 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with
47 additions and
13 deletions
Include/internal/pycore_traceback.h
Lib/test/test_sys.py
Misc/NEWS.d/next/Core and Builtins/2019-05-22-23-01-29.bpo-36829.MfOcUg.rst
Python/errors.c
Python/traceback.c
@ -86,6 +86,10 @@ PyAPI_FUNC(void) _Py_DumpHexadecimal(
unsigned long value ,
Py_ssize_t width ) ;
PyAPI_FUNC ( PyObject * ) _PyTraceBack_FromFrame (
PyObject * tb_next ,
struct _frame * frame ) ;
# ifdef __cplusplus
}
# endif
@ -882,19 +882,14 @@ class UnraisableHookTest(unittest.TestCase):
import _testcapi
import types
try :
# raise the exception to get a traceback in the except block
try :
raise exc
except Exception as exc2 :
_testcapi . write_unraisable_exc ( exc2 , obj )
return types . SimpleNamespace ( exc_type = type ( exc2 ) ,
exc_value = exc2 ,
exc_traceback = exc2 . __traceback__ ,
object = obj )
_testcapi . write_unraisable_exc ( exc , obj )
return types . SimpleNamespace ( exc_type = type ( exc ) ,
exc_value = exc ,
exc_traceback = exc . __traceback__ ,
object = obj )
finally :
# Explicitly break any reference cycle
exc = None
exc2 = None
def test_original_unraisablehook ( self ) :
obj = " an object "
@ -0,0 +1,4 @@
:c:func: `PyErr_WriteUnraisable` now creates a traceback object if there is
no current traceback. Moreover, call :c:func: `PyErr_NormalizeException` and
:c:func: `PyException_SetTraceback` to normalize the exception value. Ignore any
error.
@ -4,6 +4,7 @@
# include "Python.h"
# include "pycore_coreconfig.h"
# include "pycore_pystate.h"
# include "pycore_traceback.h"
# ifndef __STDC__
# ifndef MS_WINDOWS
@ -1048,7 +1049,7 @@ write_unraisable_exc_file(PyObject *exc_type, PyObject *exc_value,
}
}
if ( ! exc_typ e) {
if ( exc_type = = NULL | | exc_type = = Py_Non e) {
return - 1 ;
}
@ -1106,6 +1107,7 @@ write_unraisable_exc_file(PyObject *exc_type, PyObject *exc_value,
}
}
}
if ( PyFile_WriteString ( " \n " , file ) < 0 ) {
return - 1 ;
}
@ -1177,6 +1179,24 @@ PyErr_WriteUnraisable(PyObject *obj)
goto default_hook ;
}
if ( exc_tb = = NULL ) {
struct _frame * frame = _PyThreadState_GET ( ) - > frame ;
if ( frame ! = NULL ) {
exc_tb = _PyTraceBack_FromFrame ( NULL , frame ) ;
if ( exc_tb = = NULL ) {
PyErr_Clear ( ) ;
}
}
}
PyErr_NormalizeException ( & exc_type , & exc_value , & exc_tb ) ;
if ( exc_tb ! = NULL & & exc_tb ! = Py_None & & PyTraceBack_Check ( exc_tb ) ) {
if ( PyException_SetTraceback ( exc_value , exc_tb ) < 0 ) {
PyErr_Clear ( ) ;
}
}
_Py_IDENTIFIER ( unraisablehook ) ;
PyObject * hook = _PySys_GetObjectId ( & PyId_unraisablehook ) ;
if ( hook ! = NULL & & hook ! = Py_None ) {
@ -227,13 +227,24 @@ PyTypeObject PyTraceBack_Type = {
tb_new , /* tp_new */
} ;
PyObject *
_PyTraceBack_FromFrame ( PyObject * tb_next , PyFrameObject * frame )
{
assert ( tb_next = = NULL | | PyTraceBack_Check ( tb_next ) ) ;
assert ( frame ! = NULL ) ;
return tb_create_raw ( ( PyTracebackObject * ) tb_next , frame , frame - > f_lasti ,
PyFrame_GetLineNumber ( frame ) ) ;
}
int
PyTraceBack_Here ( PyFrameObject * frame )
{
PyObject * exc , * val , * tb , * newtb ;
PyErr_Fetch ( & exc , & val , & tb ) ;
newtb = tb_create_raw ( ( PyTracebackObject * ) tb , frame , frame - > f_lasti ,
PyFrame_GetLineNumber ( frame ) ) ;
newtb = _PyTraceBack_FromFrame ( tb , frame ) ;
if ( newtb = = NULL ) {
_PyErr_ChainExceptions ( exc , val , tb ) ;
return - 1 ;