bpo-36829: Add _PyErr_WriteUnraisableMsg() (GH-13488) · python/cpython@71c52e3 (original) (raw)
`@@ -1077,6 +1077,7 @@ static PyStructSequence_Field UnraisableHookArgs_fields[] = {
`
1077
1077
` {"exc_type", "Exception type"},
`
1078
1078
` {"exc_value", "Exception value"},
`
1079
1079
` {"exc_traceback", "Exception traceback"},
`
``
1080
`+
{"err_msg", "Error message"},
`
1080
1081
` {"object", "Object causing the exception"},
`
1081
1082
` {0}
`
1082
1083
`};
`
`@@ -1085,7 +1086,7 @@ static PyStructSequence_Desc UnraisableHookArgs_desc = {
`
1085
1086
` .name = "UnraisableHookArgs",
`
1086
1087
` .doc = UnraisableHookArgs__doc__,
`
1087
1088
` .fields = UnraisableHookArgs_fields,
`
1088
``
`-
.n_in_sequence = 4
`
``
1089
`+
.n_in_sequence = 5
`
1089
1090
`};
`
1090
1091
``
1091
1092
``
`@@ -1104,7 +1105,8 @@ _PyErr_Init(void)
`
1104
1105
``
1105
1106
`static PyObject *
`
1106
1107
`make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
`
1107
``
`-
PyObject *exc_value, PyObject *exc_tb, PyObject *obj)
`
``
1108
`+
PyObject *exc_value, PyObject *exc_tb,
`
``
1109
`+
PyObject *err_msg, PyObject *obj)
`
1108
1110
`{
`
1109
1111
`PyObject *args = PyStructSequence_New(&UnraisableHookArgsType);
`
1110
1112
`if (args == NULL) {
`
`@@ -1125,6 +1127,7 @@ make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
`
1125
1127
`ADD_ITEM(exc_type);
`
1126
1128
`ADD_ITEM(exc_value);
`
1127
1129
`ADD_ITEM(exc_tb);
`
``
1130
`+
ADD_ITEM(err_msg);
`
1128
1131
`ADD_ITEM(obj);
`
1129
1132
`#undef ADD_ITEM
`
1130
1133
``
`@@ -1145,11 +1148,21 @@ make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
`
1145
1148
`static int
`
1146
1149
`write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
`
1147
1150
`PyObject *exc_value, PyObject *exc_tb,
`
1148
``
`-
PyObject *obj, PyObject *file)
`
``
1151
`+
PyObject *err_msg, PyObject *obj, PyObject *file)
`
1149
1152
`{
`
1150
1153
`if (obj != NULL && obj != Py_None) {
`
1151
``
`-
if (PyFile_WriteString("Exception ignored in: ", file) < 0) {
`
1152
``
`-
return -1;
`
``
1154
`+
if (err_msg != NULL && err_msg != Py_None) {
`
``
1155
`+
if (PyFile_WriteObject(err_msg, file, Py_PRINT_RAW) < 0) {
`
``
1156
`+
return -1;
`
``
1157
`+
}
`
``
1158
`+
if (PyFile_WriteString(": ", file) < 0) {
`
``
1159
`+
return -1;
`
``
1160
`+
}
`
``
1161
`+
}
`
``
1162
`+
else {
`
``
1163
`+
if (PyFile_WriteString("Exception ignored in: ", file) < 0) {
`
``
1164
`+
return -1;
`
``
1165
`+
}
`
1153
1166
` }
`
1154
1167
``
1155
1168
`if (PyFile_WriteObject(obj, file, 0) < 0) {
`
`@@ -1162,6 +1175,14 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
`
1162
1175
`return -1;
`
1163
1176
` }
`
1164
1177
` }
`
``
1178
`+
else if (err_msg != NULL && err_msg != Py_None) {
`
``
1179
`+
if (PyFile_WriteObject(err_msg, file, Py_PRINT_RAW) < 0) {
`
``
1180
`+
return -1;
`
``
1181
`+
}
`
``
1182
`+
if (PyFile_WriteString(":\n", file) < 0) {
`
``
1183
`+
return -1;
`
``
1184
`+
}
`
``
1185
`+
}
`
1165
1186
``
1166
1187
`if (exc_tb != NULL && exc_tb != Py_None) {
`
1167
1188
`if (PyTraceBack_Print(exc_tb, file) < 0) {
`
`@@ -1178,8 +1199,9 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
`
1178
1199
`const char *className = PyExceptionClass_Name(exc_type);
`
1179
1200
`if (className != NULL) {
`
1180
1201
`const char *dot = strrchr(className, '.');
`
1181
``
`-
if (dot != NULL)
`
``
1202
`+
if (dot != NULL) {
`
1182
1203
`className = dot+1;
`
``
1204
`+
}
`
1183
1205
` }
`
1184
1206
``
1185
1207
`_Py_IDENTIFIER(module);
`
`@@ -1238,7 +1260,8 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
`
1238
1260
``
1239
1261
`static int
`
1240
1262
`write_unraisable_exc(PyThreadState *tstate, PyObject *exc_type,
`
1241
``
`-
PyObject *exc_value, PyObject *exc_tb, PyObject *obj)
`
``
1263
`+
PyObject *exc_value, PyObject *exc_tb, PyObject *err_msg,
`
``
1264
`+
PyObject *obj)
`
1242
1265
`{
`
1243
1266
`PyObject *file = _PySys_GetObjectId(&PyId_stderr);
`
1244
1267
`if (file == NULL || file == Py_None) {
`
`@@ -1249,7 +1272,7 @@ write_unraisable_exc(PyThreadState *tstate, PyObject *exc_type,
`
1249
1272
` while we use it */
`
1250
1273
`Py_INCREF(file);
`
1251
1274
`int res = write_unraisable_exc_file(tstate, exc_type, exc_value, exc_tb,
`
1252
``
`-
obj, file);
`
``
1275
`+
err_msg, obj, file);
`
1253
1276
`Py_DECREF(file);
`
1254
1277
``
1255
1278
`return res;
`
`@@ -1272,9 +1295,10 @@ _PyErr_WriteUnraisableDefaultHook(PyObject *args)
`
1272
1295
`PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0);
`
1273
1296
`PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1);
`
1274
1297
`PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2);
`
1275
``
`-
PyObject *obj = PyStructSequence_GET_ITEM(args, 3);
`
``
1298
`+
PyObject *err_msg = PyStructSequence_GET_ITEM(args, 3);
`
``
1299
`+
PyObject *obj = PyStructSequence_GET_ITEM(args, 4);
`
1276
1300
``
1277
``
`-
if (write_unraisable_exc(tstate, exc_type, exc_value, exc_tb, obj) < 0) {
`
``
1301
`+
if (write_unraisable_exc(tstate, exc_type, exc_value, exc_tb, err_msg, obj) < 0) {
`
1278
1302
`return NULL;
`
1279
1303
` }
`
1280
1304
`Py_RETURN_NONE;
`
`@@ -1287,13 +1311,18 @@ _PyErr_WriteUnraisableDefaultHook(PyObject *args)
`
1287
1311
` for Python to handle it. For example, when a destructor raises an exception
`
1288
1312
` or during garbage collection (gc.collect()).
`
1289
1313
``
``
1314
`+
If err_msg_str is non-NULL, the error message is formatted as:
`
``
1315
`+
"Exception ignored %s" % err_msg_str. Otherwise, use "Exception ignored in"
`
``
1316
`+
error message.
`
``
1317
+
1290
1318
` An exception must be set when calling this function. */
`
1291
1319
`void
`
1292
``
`-
PyErr_WriteUnraisable(PyObject *obj)
`
``
1320
`+
_PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj)
`
1293
1321
`{
`
1294
1322
`PyThreadState *tstate = _PyThreadState_GET();
`
1295
1323
`assert(tstate != NULL);
`
1296
1324
``
``
1325
`+
PyObject *err_msg = NULL;
`
1297
1326
`PyObject *exc_type, *exc_value, *exc_tb;
`
1298
1327
`_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
`
1299
1328
``
`@@ -1322,13 +1351,20 @@ PyErr_WriteUnraisable(PyObject *obj)
`
1322
1351
` }
`
1323
1352
` }
`
1324
1353
``
``
1354
`+
if (err_msg_str != NULL) {
`
``
1355
`+
err_msg = PyUnicode_FromFormat("Exception ignored %s", err_msg_str);
`
``
1356
`+
if (err_msg == NULL) {
`
``
1357
`+
PyErr_Clear();
`
``
1358
`+
}
`
``
1359
`+
}
`
``
1360
+
1325
1361
`_Py_IDENTIFIER(unraisablehook);
`
1326
1362
`PyObject *hook = _PySys_GetObjectId(&PyId_unraisablehook);
`
1327
1363
`if (hook != NULL && hook != Py_None) {
`
1328
1364
`PyObject *hook_args;
`
1329
1365
``
1330
1366
`hook_args = make_unraisable_hook_args(tstate, exc_type, exc_value,
`
1331
``
`-
exc_tb, obj);
`
``
1367
`+
exc_tb, err_msg, obj);
`
1332
1368
`if (hook_args != NULL) {
`
1333
1369
`PyObject *args[1] = {hook_args};
`
1334
1370
`PyObject *res = _PyObject_FastCall(hook, args, 1);
`
`@@ -1337,6 +1373,18 @@ PyErr_WriteUnraisable(PyObject *obj)
`
1337
1373
`Py_DECREF(res);
`
1338
1374
` goto done;
`
1339
1375
` }
`
``
1376
+
``
1377
`+
err_msg_str = "Exception ignored in sys.unraisablehook";
`
``
1378
`+
}
`
``
1379
`+
else {
`
``
1380
`+
err_msg_str = ("Exception ignored on building "
`
``
1381
`+
"sys.unraisablehook arguments");
`
``
1382
`+
}
`
``
1383
+
``
1384
`+
Py_XDECREF(err_msg);
`
``
1385
`+
err_msg = PyUnicode_FromString(err_msg_str);
`
``
1386
`+
if (err_msg == NULL) {
`
``
1387
`+
PyErr_Clear();
`
1340
1388
` }
`
1341
1389
``
1342
1390
`/* sys.unraisablehook failed: log its error using default hook */
`
`@@ -1350,15 +1398,25 @@ PyErr_WriteUnraisable(PyObject *obj)
`
1350
1398
``
1351
1399
`default_hook:
`
1352
1400
`/* Call the default unraisable hook (ignore failure) */
`
1353
``
`-
(void)write_unraisable_exc(tstate, exc_type, exc_value, exc_tb, obj);
`
``
1401
`+
(void)write_unraisable_exc(tstate, exc_type, exc_value, exc_tb,
`
``
1402
`+
err_msg, obj);
`
1354
1403
``
1355
1404
`done:
`
1356
1405
`Py_XDECREF(exc_type);
`
1357
1406
`Py_XDECREF(exc_value);
`
1358
1407
`Py_XDECREF(exc_tb);
`
``
1408
`+
Py_XDECREF(err_msg);
`
1359
1409
`_PyErr_Clear(tstate); /* Just in case */
`
1360
1410
`}
`
1361
1411
``
``
1412
+
``
1413
`+
void
`
``
1414
`+
PyErr_WriteUnraisable(PyObject *obj)
`
``
1415
`+
{
`
``
1416
`+
_PyErr_WriteUnraisableMsg(NULL, obj);
`
``
1417
`+
}
`
``
1418
+
``
1419
+
1362
1420
`extern PyObject *PyModule_GetWarningsModule(void);
`
1363
1421
``
1364
1422
``