bpo-36829: Enhance PyErr_WriteUnraisable() (GH-13487) · python/cpython@a58db96 (original) (raw)
`@@ -940,90 +940,121 @@ PyErr_NewExceptionWithDoc(const char *name, const char *doc,
`
940
940
`}
`
941
941
``
942
942
``
943
``
`-
/* Call when an exception has occurred but there is no way for Python
`
944
``
`-
to handle it. Examples: exception in del or during GC. */
`
945
``
`-
void
`
946
``
`-
PyErr_WriteUnraisable(PyObject *obj)
`
``
943
`+
static void
`
``
944
`+
write_unraisable_exc_file(PyObject *exc_type, PyObject *exc_value,
`
``
945
`+
PyObject *exc_tb, PyObject *obj, PyObject *file)
`
947
946
`{
`
948
``
`-
_Py_IDENTIFIER(module);
`
949
``
`-
PyObject *f, *t, *v, *tb;
`
950
``
`-
PyObject *moduleName = NULL;
`
951
``
`-
char* className;
`
952
``
-
953
``
`-
PyErr_Fetch(&t, &v, &tb);
`
954
``
-
955
``
`-
f = _PySys_GetObjectId(&PyId_stderr);
`
956
``
`-
if (f == NULL || f == Py_None)
`
957
``
`-
goto done;
`
958
``
-
959
947
`if (obj) {
`
960
``
`-
if (PyFile_WriteString("Exception ignored in: ", f) < 0)
`
961
``
`-
goto done;
`
962
``
`-
if (PyFile_WriteObject(obj, f, 0) < 0) {
`
``
948
`+
if (PyFile_WriteString("Exception ignored in: ", file) < 0) {
`
``
949
`+
return;
`
``
950
`+
}
`
``
951
`+
if (PyFile_WriteObject(obj, file, 0) < 0) {
`
963
952
`PyErr_Clear();
`
964
``
`-
if (PyFile_WriteString("<object repr() failed>", f) < 0) {
`
965
``
`-
goto done;
`
``
953
`+
if (PyFile_WriteString("<object repr() failed>", file) < 0) {
`
``
954
`+
return;
`
966
955
` }
`
967
956
` }
`
968
``
`-
if (PyFile_WriteString("\n", f) < 0)
`
969
``
`-
goto done;
`
``
957
`+
if (PyFile_WriteString("\n", file) < 0) {
`
``
958
`+
return;
`
``
959
`+
}
`
970
960
` }
`
971
961
``
972
``
`-
if (PyTraceBack_Print(tb, f) < 0)
`
973
``
`-
goto done;
`
``
962
`+
if (exc_tb != NULL) {
`
``
963
`+
if (PyTraceBack_Print(exc_tb, file) < 0) {
`
``
964
`+
/* continue even if writing the traceback failed */
`
``
965
`+
PyErr_Clear();
`
``
966
`+
}
`
``
967
`+
}
`
974
968
``
975
``
`-
if (!t)
`
976
``
`-
goto done;
`
``
969
`+
if (!exc_type) {
`
``
970
`+
return;
`
``
971
`+
}
`
977
972
``
978
``
`-
assert(PyExceptionClass_Check(t));
`
979
``
`-
className = PyExceptionClass_Name(t);
`
``
973
`+
assert(PyExceptionClass_Check(exc_type));
`
``
974
`+
char* className = PyExceptionClass_Name(exc_type);
`
980
975
`if (className != NULL) {
`
981
976
`char *dot = strrchr(className, '.');
`
982
``
`-
if (dot != NULL)
`
``
977
`+
if (dot != NULL) {
`
983
978
`className = dot+1;
`
``
979
`+
}
`
984
980
` }
`
985
981
``
986
``
`-
moduleName = PyObject_GetAttrId(t, &PyId___module_);
`
``
982
`+
_Py_IDENTIFIER(module);
`
``
983
`+
PyObject *moduleName = PyObject_GetAttrId(exc_type, &PyId___module_);
`
987
984
`if (moduleName == NULL || !PyUnicode_Check(moduleName)) {
`
``
985
`+
Py_XDECREF(moduleName);
`
988
986
`PyErr_Clear();
`
989
``
`-
if (PyFile_WriteString("", f) < 0)
`
990
``
`-
goto done;
`
``
987
`+
if (PyFile_WriteString("", file) < 0) {
`
``
988
`+
return;
`
``
989
`+
}
`
991
990
` }
`
992
991
`else {
`
993
992
`if (!_PyUnicode_EqualToASCIIId(moduleName, &PyId_builtins)) {
`
994
``
`-
if (PyFile_WriteObject(moduleName, f, Py_PRINT_RAW) < 0)
`
995
``
`-
goto done;
`
996
``
`-
if (PyFile_WriteString(".", f) < 0)
`
997
``
`-
goto done;
`
``
993
`+
if (PyFile_WriteObject(moduleName, file, Py_PRINT_RAW) < 0) {
`
``
994
`+
Py_DECREF(moduleName);
`
``
995
`+
return;
`
``
996
`+
}
`
``
997
`+
Py_DECREF(moduleName);
`
``
998
`+
if (PyFile_WriteString(".", file) < 0) {
`
``
999
`+
return;
`
``
1000
`+
}
`
``
1001
`+
}
`
``
1002
`+
else {
`
``
1003
`+
Py_DECREF(moduleName);
`
998
1004
` }
`
999
1005
` }
`
``
1006
+
1000
1007
`if (className == NULL) {
`
1001
``
`-
if (PyFile_WriteString("", f) < 0)
`
1002
``
`-
goto done;
`
``
1008
`+
if (PyFile_WriteString("", file) < 0) {
`
``
1009
`+
return;
`
``
1010
`+
}
`
1003
1011
` }
`
1004
1012
`else {
`
1005
``
`-
if (PyFile_WriteString(className, f) < 0)
`
1006
``
`-
goto done;
`
``
1013
`+
if (PyFile_WriteString(className, file) < 0) {
`
``
1014
`+
return;
`
``
1015
`+
}
`
1007
1016
` }
`
1008
1017
``
1009
``
`-
if (v && v != Py_None) {
`
1010
``
`-
if (PyFile_WriteString(": ", f) < 0)
`
1011
``
`-
goto done;
`
1012
``
`-
if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0) {
`
``
1018
`+
if (exc_value && exc_value != Py_None) {
`
``
1019
`+
if (PyFile_WriteString(": ", file) < 0) {
`
``
1020
`+
return;
`
``
1021
`+
}
`
``
1022
`+
if (PyFile_WriteObject(exc_value, file, Py_PRINT_RAW) < 0) {
`
1013
1023
`PyErr_Clear();
`
1014
``
`-
if (PyFile_WriteString("<exception str() failed>", f) < 0) {
`
1015
``
`-
goto done;
`
``
1024
`+
if (PyFile_WriteString("<exception str() failed>", file) < 0) {
`
``
1025
`+
return;
`
1016
1026
` }
`
1017
1027
` }
`
1018
1028
` }
`
1019
``
`-
if (PyFile_WriteString("\n", f) < 0)
`
1020
``
`-
goto done;
`
``
1029
`+
if (PyFile_WriteString("\n", file) < 0) {
`
``
1030
`+
return;
`
``
1031
`+
}
`
``
1032
`+
}
`
1021
1033
``
1022
``
`-
done:
`
1023
``
`-
Py_XDECREF(moduleName);
`
1024
``
`-
Py_XDECREF(t);
`
1025
``
`-
Py_XDECREF(v);
`
1026
``
`-
Py_XDECREF(tb);
`
``
1034
+
``
1035
`+
/* Display an unraisable exception into sys.stderr.
`
``
1036
+
``
1037
`+
Called when an exception has occurred but there is no way for Python to
`
``
1038
`+
handle it. For example, when a destructor raises an exception or during
`
``
1039
`+
garbage collection (gc.collect()).
`
``
1040
+
``
1041
`+
An exception must be set when calling this function. */
`
``
1042
`+
void
`
``
1043
`+
PyErr_WriteUnraisable(PyObject *obj)
`
``
1044
`+
{
`
``
1045
`+
PyObject *f, *exc_type, *exc_value, *exc_tb;
`
``
1046
+
``
1047
`+
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
`
``
1048
+
``
1049
`+
f = _PySys_GetObjectId(&PyId_stderr);
`
``
1050
`+
/* Do nothing if sys.stderr is not available or set to None */
`
``
1051
`+
if (f != NULL && f != Py_None) {
`
``
1052
`+
write_unraisable_exc_file(exc_type, exc_value, exc_tb, obj, f);
`
``
1053
`+
}
`
``
1054
+
``
1055
`+
Py_XDECREF(exc_type);
`
``
1056
`+
Py_XDECREF(exc_value);
`
``
1057
`+
Py_XDECREF(exc_tb);
`
1027
1058
`PyErr_Clear(); /* Just in case */
`
1028
1059
`}
`
1029
1060
``