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

``