8000 gh-108082: Use PyErr_FormatUnraisable() (GH-111580) · python/cpython@970e719 · GitHub
[go: up one dir, main page]

Skip to content

Commit 970e719

Browse files
gh-108082: Use PyErr_FormatUnraisable() (GH-111580)
Replace most of calls of _PyErr_WriteUnraisableMsg() and some calls of PyErr_WriteUnraisable(NULL) with PyErr_FormatUnraisable(). Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent a12f624 commit 970e719

18 files changed

+83
-114
lines changed

Lib/test/test_capi/test_watchers.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ def test_error(self):
110110
with catch_unraisable_exception() as cm:
111111
d["foo"] = "bar"
112112
self.assertIn(
113-
"PyDict_EVENT_ADDED watcher callback for <dict at",
114-
cm.unraisable.object
113+
"Exception ignored in "
114+
"PyDict_EVENT_ADDED watcher callback for <dict at ",
115+
cm.unraisable.err_msg
115116
)
117+
self.assertIsNone(cm.unraisable.object)
116118
self.assertEqual(str(cm.unraisable.exc_value), "boom!")
117119
self.assert_events([])
118120

@@ -278,7 +280,9 @@ class C: pass
278280
self.watch(wid, C)
279281
with catch_unraisable_exception() as cm:
280282
C.foo = "bar"
281-
self.assertIs(cm.unraisable.object, C)
283+
self.assertEqual(cm.unraisable.err_msg,
284+
f"Exception ignored in type watcher callback #0 for {C!r}")
285+
self.assertIs(cm.unraisable.object, None)
282286
self.assertEqual(str(cm.unraisable.exc_value), "boom!")
283287
self.assert_events([])
284288

@@ -416,9 +420,11 @@ def test_error(self):
416420
co = _testcapi.code_newempty("test_watchers", "dummy0", 0)
417421

418422
self.assertEqual(
419-
cm.unraisable.object,
423+
cm.unraisable.err_msg,
424+
f"Exception ignored in "
420425
f"PY_CODE_EVENT_CREATE watcher callback for {co!r}"
421426
)
427+
self.assertIsNone(cm.unraisable.object)
422428
self.assertEqual(str(cm.unraisable.exc_value), "boom!")
423429

424430
def test_dealloc_error(self):
@@ -520,9 +526,11 @@ def myfunc():
520526
pass
521527

522528
self.assertEqual(
523-
cm.unraisable.object,
524-
f"PyFunction_EVENT_CREATE watcher callback for {myfunc!r}"
529+
cm.unraisable.err_msg,
530+
f"Exception ignored in "
531+
f"PyFunction_EVENT_CREATE watcher callback for {repr(myfunc)[1:-1]}"
525532
)
533+
self.assertIsNone(cm.unraisable.object)
526534

527535
def test_dealloc_watcher_raises_error(self):
528536
class MyError(Exception):

Lib/test/test_cmd_line.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,9 @@ def test_stdout_flush_at_shutdown(self):
479479
rc, out, err = assert_python_failure('-c', code)
480480
self.assertEqual(b'', out)
481481
self.assertEqual(120, rc)
482-
self.assertRegex(err.decode('ascii', 'ignore'),
483-
'Exception ignored in.*\nOSError: .*')
482+
self.assertIn(b'Exception ignored on flushing sys.stdout:\n'
483+
b'OSError: '.replace(b'\n', os.linesep.encode()),
484+
err)
484485

485486
def test_closed_stdout(self):
486487
# Issue #13444: if stdout has been explicitly closed, we should

Modules/_ctypes/_ctypes.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ bytes(cdata)
113113
#ifdef MS_WIN32
114114
# include "pycore_modsupport.h" // _PyArg_NoKeywords()
115115
#endif
116-
#include "pycore_pyerrors.h" // _PyErr_WriteUnraisableMsg()
117116

118117

119118
#include <ffi.h>
@@ -185,7 +184,7 @@ _DictRemover_call(PyObject *myself, PyObject *args, PyObject *kw)
185184
DictRemoverObject *self = (DictRemoverObject *)myself;
186185
if (self->key && self->dict) {
187186
if (-1 == PyDict_DelItem(self->dict, self->key)) {
188-
_PyErr_WriteUnraisableMsg("on calling _ctypes.DictRemover", NULL);
187+
PyErr_FormatUnraisable("Exception ignored on calling _ctypes.DictRemover");
189188
}
190189
Py_CLEAR(self->key);
191190
Py_CLEAR(self->dict);

Modules/_lsprof.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include "Python.h"
66
#include "pycore_call.h" // _PyObject_CallNoArgs()
77
#include "pycore_ceval.h" // _PyEval_SetProfile()
8-
#include "pycore_pyerrors.h" // _PyErr_WriteUnraisableMsg()
98
#include "pycore_pystate.h" // _PyThreadState_GET()
109

1110
#include "rotatingtree.h"
@@ -847,7 +846,7 @@ profiler_dealloc(ProfilerObject *op)
847846
if (op->flags & POF_ENABLED) {
848847
PyThreadState *tstate = _PyThreadState_GET();
849848
if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
850-
_PyErr_WriteUnraisableMsg("When destroying _lsprof profiler", NULL);
849+
PyErr_FormatUnraisable("Exception ignored when destroying _lsprof profiler");
851850
}
852851
}
853852

Modules/gcmodule.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,8 +1032,8 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
10321032
Py_INCREF(op);
10331033
(void) clear(op);
10341034
if (_PyErr_Occurred(tstate)) {
1035-
_PyErr_WriteUnraisableMsg("in tp_clear of",
1036-
(PyObject*)Py_TYPE(op));
1035+
PyErr_FormatUnraisable("Exception ignored in tp_clear of %s",
1036+
Py_TYPE(op)->tp_name);
10371037
}
10381038
Py_DECREF(op);
10391039
}
@@ -1344,7 +1344,7 @@ gc_collect_main(PyThreadState *tstate, int generation,
13441344
_PyErr_Clear(tstate);
13451345
}
13461346
else {
1347-
_PyErr_WriteUnraisableMsg("in garbage collection", NULL);
1347+
PyErr_FormatUnraisable("Exception ignored in garbage collection");
13481348
}
13491349
}
13501350

@@ -1403,15 +1403,15 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase,
14031403
"collected", collected,
14041404
"uncollectable", uncollectable);
14051405
if (info == NULL) {
1406-
PyErr_WriteUnraisable(NULL);
1406+
PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks");
14071407
return;
14081408
}
14091409
}
14101410

14111411
PyObject *phase_obj = PyUnicode_FromString(phase);
14121412
if (phase_obj == NULL) {
14131413
Py_XDECREF(info);
1414-
PyErr_WriteUnraisable(NULL);
1414+
PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks");
14151415
return;
14161416
}
14171417

Modules/getpath.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include "pycore_fileutils.h" // _Py_abspath()
55
#include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
66
#include "pycore_pathconfig.h" // _PyPathConfig_ReadGlobal()
7-
#include "pycore_pyerrors.h" // _PyErr_WriteUnraisableMsg()
87
#include "pycore_pymem.h" // _PyMem_RawWcsdup()
98
#include "pycore_pystate.h" // _PyThreadState_GET()
109

@@ -911,7 +910,7 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
911910
) {
912911
Py_DECREF(co);
913912
Py_DECREF(dict);
914-
_PyErr_WriteUnraisableMsg("error evaluating initial values", NULL);
913+
PyErr_FormatUnraisable("Exception ignored in preparing getpath");
915914
return PyStatus_Error("error evaluating initial values");
916915
}
917916

@@ -920,13 +919,13 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
920919

921920
if (!r) {
922921
Py_DECREF(dict);
923-
_PyErr_WriteUnraisableMsg("error evaluating path", NULL);
922+
PyErr_FormatUnraisable("Exception ignored in running getpath");
924923
return PyStatus_Error("error evaluating path");
925924
}
926925
Py_DECREF(r);
927926

928927
if (_PyConfig_FromDict(config, configDict) < 0) {
929-
_PyErr_WriteUnraisableMsg("reading getpath results", NULL);
928+
PyErr_FormatUnraisable("Exception ignored in reading getpath results");
930929
Py_DECREF(dict);
931930
return PyStatus_Error("error getting getpath results");
932931
}

Modules/signalmodule.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ report_wakeup_write_error(void *data)
244244
errno = (int) (intptr_t) data;
245245
PyObject *exc = PyErr_GetRaisedException();
246246
PyErr_SetFromErrno(PyExc_OSError);
247-
_PyErr_WriteUnraisableMsg("when trying to write to the signal wakeup fd",
248-
NULL);
247+
PyErr_FormatUnraisable("Exception ignored when trying to write to the signal wakeup fd");
249248
PyErr_SetRaisedException(exc);
250249
errno = save_errno;
251250
return 0;
@@ -262,7 +261,7 @@ report_wakeup_send_error(void* data)
262261
recognizes the error codes used by both GetLastError() and
263262
WSAGetLastError */
264263
PyErr_SetExcFromWindowsErr(PyExc_OSError, send_errno);
265-
_PyErr_WriteUnraisableMsg("when trying to send to the signal wakeup fd", NULL);
264+
PyErr_FormatUnraisable("Exception ignored when trying to send to the signal wakeup fd");
266265
PyErr_SetRaisedException(exc);
267266
return 0;
268267
}

Objects/codeobject.c

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
#include "pycore_tuple.h" // _PyTuple_ITEMS()
1313
#include "clinic/codeobject.c.h"
1414

15-
static PyObject* code_repr(PyCodeObject *co);
16-
1715
static const char *
1816
code_event_name(PyCodeEvent event) {
1917
switch (event) {
@@ -41,21 +39,9 @@ notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
4139
// callback must be non-null if the watcher bit is set
4240
assert(cb != NULL);
4341
if (cb(event, co) < 0) {
44-
// Don't risk resurrecting the object if an unraisablehook keeps
45-
// a reference; pass a string as context.
46-
PyObject *context = NULL;
47-
PyObject *repr = code_repr(co);
48-
if (repr) {
49-
context = PyUnicode_FromFormat(
50-
"%s watcher callback for %U",
51-
code_event_name(event), repr);
52-
Py_DECREF(repr);
53-
}
54-
if (context == NULL) {
55-
context = Py_NewRef(Py_None);
56-
}
57-
PyErr_WriteUnraisable(context);
58-
Py_DECREF(context);
42+
PyErr_FormatUnraisable(
43+
"Exception ignored in %s watcher callback for %R",
44+
code_event_name(event), co);
5945
}
6046
}
6147
i++;

Objects/dictobject.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5912,14 +5912,9 @@ _PyDict_SendEvent(int watcher_bits,
59125912
// unraisablehook keep a reference to it, so we don't pass the
59135913
// dict as context, just an informative string message. Dict
59145914
// repr can call arbitrary code, so we invent a simpler version.
5915-
PyObject *context = PyUnicode_FromFormat(
5916-
"%s watcher callback for <dict at %p>",
5915+
PyErr_FormatUnraisable(
5916+
"Exception ignored in %s watcher callback for <dict at %p>",
59175917
dict_event_name(event), mp);
5918-
if (context == NULL) {
5919-
context = Py_NewRef(Py_None);
5920-
}
5921-
PyErr_WriteUnraisable(context);
5922-
Py_DECREF(context);
59235918
}
59245919
}
59255920
watcher_bits >>= 1;

Objects/funcobject.c

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
#include "pycore_pyerrors.h" // _PyErr_Occurred()
99

1010

11-
static PyObject* func_repr(PyFunctionObject *op);
12-
1311
static const char *
1412
func_event_name(PyFunction_WatchEvent event) {
1513
switch (event) {
@@ -35,21 +33,9 @@ notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
3533
// callback must be non-null if the watcher bit is set
3634
assert(cb != NULL);
3735
if (cb(event, func, new_value) < 0) {
38-
// Don't risk resurrecting the func if an unraisablehook keeps a
39-
// reference; pass a string as context.
40-
PyObject *context = NULL;
41-
PyObject *repr = func_repr(func);
42-
if (repr != NULL) {
43-
context = PyUnicode_FromFormat(
44-
"%s watcher callback for %U",
45-
func_event_name(event), repr);
46-
Py_DECREF(repr);
47-
}
48-
if (context == NULL) {
49-
context = Py_NewRef(Py_None);
50-
}
51-
PyErr_WriteUnraisable(context);
52-
Py_DECREF(context);
36+
PyErr_FormatUnraisable(
37+
"Exception ignored in %s watcher callback for function %U at %p",
38+
func_event_name(event), func->func_qualname, func);
5339
}
5440
}
5541
i++;

Objects/moduleobject.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ _PyModule_ClearDict(PyObject *d)
647647
PyErr_Clear();
648648
}
649649
if (PyDict_SetItem(d, key, Py_None) != 0) {
650-
PyErr_WriteUnraisable(NULL);
650+
PyErr_FormatUnraisable("Exception ignored on clearing module dict");
651651
}
652652
}
653653
}
@@ -668,7 +668,7 @@ _PyModule_ClearDict(PyObject *d)
668668
PyErr_Clear();
669669
}
670670
if (PyDict_SetItem(d, key, Py_None) != 0) {
671-
PyErr_WriteUnraisable(NULL);
671+
PyErr_FormatUnraisable("Exception ignored on clearing module dict");
672672
}
673673
}
674674
}
@@ -902,10 +902,9 @@ module_clear(PyModuleObject *m)
902902
{
903903
int res = m->md_def->m_clear((PyObject*)m);
904904
if (PyErr_Occurred()) {
905-
PySys_FormatStderr("Exception ignored in m_clear of module%s%V\n",
906-
m->md_name ? " " : "",
907-
m->md_name, "");
908-
PyErr_WriteUnraisable(NULL);
905+
PyErr_FormatUnraisable("Exception ignored in m_clear of module%s%V",
906+
m->md_name ? " " : "",
907+
m->md_name, "");
909908
}
910909
if (res)
911910
return res;

Objects/typeobject.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,9 @@ PyType_Modified(PyTypeObject *type)
828828
if (bits & 1) {
829829
PyType_WatchCallback cb = interp->type_watchers[i];
830830
if (cb && (cb(type) < 0)) {
831-
PyErr_WriteUnraisable((PyObject *)type);
831+
PyErr_FormatUnraisable(
832+
"Exception ignored in type watcher callback #%d for %R",
833+
i, type);
832834
}
833835
}
834836
i++;
@@ -9291,7 +9293,7 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
92919293
// from a Python __buffer__ function.
92929294
mv = PyMemoryView_FromBuffer(buffer);
92939295
if (mv == NULL) {
9294-
PyErr_WriteUnraisable(self);
9296+
PyErr_FormatUnraisable("Exception ignored in bf_releasebuffer of %s", Py_TYPE(self)->tp_name);
92959297
goto end;
92969298
}
92979299
// Set the memoryview to restricted mode, which forbids
@@ -9304,15 +9306,15 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
93049306
PyObject *stack[2] = {self, mv};
93059307
PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2);
93069308
if (ret == NULL) {
9307-
PyErr_WriteUnraisable(self);
9309+
PyErr_FormatUnraisable("Exception ignored in __release_buffer__ of %s", Py_TYPE(self)->tp_name);
93089310
}
93099311
else {
93109312
Py_DECREF(ret);
93119313
}
93129314
if (!is_buffer_wrapper) {
93139315
PyObject *res = PyObject_CallMethodNoArgs(mv, &_Py_ID(release));
93149316
if (res == NULL) {
9315-
PyErr_WriteUnraisable(self);
9317+
PyErr_FormatUnraisable("Exception ignored in bf_releasebuffer of %s", Py_TYPE(self)->tp_name);
93169318
}
93179319
else {
93189320
Py_DECREF(res);

Python/ceval.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,7 +2235,7 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
22352235
PyThreadState *tstate = _PyThreadState_GET();
22362236
if (_PyEval_SetProfile(tstate, func, arg) < 0) {
22372237
/* Log _PySys_Audit() error */
2238-
_PyErr_WriteUnraisableMsg("in PyEval_SetProfile", NULL);
2238+
PyErr_FormatUnraisable("Exception ignored in PyEval_SetProfile");
22392239
}
22402240
}
22412241

@@ -2252,7 +2252,7 @@ PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg)
22522252

22532253
while (ts) {
22542254
if (_PyEval_SetProfile(ts, func, arg) < 0) {
2255-
_PyErr_WriteUnraisableMsg("in PyEval_SetProfileAllThreads", NULL);
2255+
PyErr_FormatUnraisable("Exception ignored in PyEval_SetProfileAllThreads");
22562256
}
22572257
HEAD_LOCK(runtime);
22582258
ts = PyThreadState_Next(ts);
@@ -2266,7 +2266,7 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
22662266
PyThreadState *tstate = _PyThreadState_GET();
22672267
if (_PyEval_SetTrace(tstate, func, arg) < 0) {
22682268
/* Log _PySys_Audit() error */
2269-
_PyErr_WriteUnraisableMsg("in PyEval_SetTrace", NULL);
2269+
PyErr_FormatUnraisable("Exception ignored in PyEval_SetTrace");
22702270
}
22712271
}
22722272

@@ -2283,7 +2283,7 @@ PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *arg)
22832283

22842284
while (ts) {
22852285
if (_PyEval_SetTrace(ts, func, arg) < 0) {
2286-
_PyErr_WriteUnraisableMsg("in PyEval_SetTraceAllThreads", NULL);
2286+
PyErr_FormatUnraisable("Exception ignored in PyEval_SetTraceAllThreads");
22872287
}
22882288
HEAD_LOCK(runtime);
22892289
ts = PyThreadState_Next(ts);

Python/compile.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include "pycore_flowgraph.h"
3535
#include "pycore_intrinsics.h"
3636
#include "pycore_long.h" // _PyLong_GetZero()
37-
#include "pycore_pyerrors.h" // _PyErr_WriteUnraisableMsg()
3837
#include "pycore_pystate.h" // _Py_GetConfig()
3938
#include "pycore_setobject.h" // _PySet_NextEntry()
4039
#include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST()
@@ -1407,8 +1406,8 @@ compiler_exit_scope(struct compiler *c)
14071406
assert(c->u);
14081407
/* we are deleting from a list so this really shouldn't fail */
14091408
if (PySequence_DelItem(c->c_stack, n) < 0) {
1410-
_PyErr_WriteUnraisableMsg("on removing the last compiler "
1411-
"stack item", NULL);
1409+
PyErr_FormatUnraisable("Exception ignored on removing "
1410+
"the last compiler stack item");
14121411
}
14131412
}
14141413
else {

0 commit comments

Comments
 (0)
0