Skip to content

Commit 8e8167d

Browse files
committed
pythongh-129354: Use PyErr_FormatUnraisable() function
Replace PyErr_WriteUnraisable() with PyErr_FormatUnraisable().
1 parent 7ec1742 commit 8e8167d

35 files changed

+213
-137
lines changed

Lib/test/test_coroutines.py

-2
Original file line numberDiff line numberDiff line change
@@ -2137,7 +2137,6 @@ async def func(): pass
21372137
support.gc_collect()
21382138

21392139
self.assertIn("was never awaited", str(cm.unraisable.exc_value))
2140-
self.assertEqual(repr(cm.unraisable.object), coro_repr)
21412140

21422141
def test_for_assign_raising_stop_async_iteration(self):
21432142
class BadTarget:
@@ -2414,7 +2413,6 @@ async def corofn():
24142413
del coro
24152414
support.gc_collect()
24162415

2417-
self.assertEqual(repr(cm.unraisable.object), coro_repr)
24182416
self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError)
24192417

24202418
del warnings._warn_unawaited_coroutine

Lib/test/test_exceptions.py

-1
Original file line numberDiff line numberDiff line change
@@ -1681,7 +1681,6 @@ def __del__(self):
16811681
del obj
16821682

16831683
gc_collect() # For PyPy or other GCs.
1684-
self.assertEqual(cm.unraisable.object, BrokenDel.__del__)
16851684
self.assertIsNotNone(cm.unraisable.exc_traceback)
16861685

16871686
def test_unhandled(self):

Lib/test/test_generators.py

-2
Original file line numberDiff line numberDiff line change
@@ -2779,14 +2779,12 @@ def printsolution(self, x):
27792779
... l = Leaker()
27802780
... del l
27812781
...
2782-
... cm.unraisable.object == Leaker.__del__
27832782
... cm.unraisable.exc_type == RuntimeError
27842783
... str(cm.unraisable.exc_value) == "del failed"
27852784
... cm.unraisable.exc_traceback is not None
27862785
True
27872786
True
27882787
True
2789-
True
27902788
27912789
27922790
These refleak tests should perhaps be in a testfile of their own,

Lib/test/test_sqlite3/test_hooks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def progress():
196196
con.execute("select 1 union select 2 union select 3").fetchall()
197197
self.assertEqual(action, 0, "progress handler was not cleared")
198198

199-
@with_tracebacks(ZeroDivisionError, name="bad_progress")
199+
@with_tracebacks(ZeroDivisionError, msg_regex="bad_progress")
200200
def test_error_in_progress_handler(self):
201201
def bad_progress():
202202
1 / 0
@@ -206,7 +206,7 @@ def bad_progress():
206206
create table foo(a, b)
207207
""")
208208

209-
@with_tracebacks(ZeroDivisionError, name="bad_progress")
209+
@with_tracebacks(ZeroDivisionError, msg_regex="bad_progress")
210210
def test_error_in_progress_handler_result(self):
211211
class BadBool:
212212
def __bool__(self):

Lib/test/test_sqlite3/test_userfunctions.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -254,22 +254,22 @@ def test_func_return_nan(self):
254254
cur.execute("select returnnan()")
255255
self.assertIsNone(cur.fetchone()[0])
256256

257-
@with_tracebacks(ZeroDivisionError, name="func_raiseexception")
257+
@with_tracebacks(ZeroDivisionError, msg_regex="func_raiseexception")
258258
def test_func_exception(self):
259259
cur = self.con.cursor()
260260
with self.assertRaises(sqlite.OperationalError) as cm:
261261
cur.execute("select raiseexception()")
262262
cur.fetchone()
263263
self.assertEqual(str(cm.exception), 'user-defined function raised exception')
264264

265-
@with_tracebacks(MemoryError, name="func_memoryerror")
265+
@with_tracebacks(MemoryError, msg_regex="func_memoryerror")
266266
def test_func_memory_error(self):
267267
cur = self.con.cursor()
268268
with self.assertRaises(MemoryError):
269269
cur.execute("select memoryerror()")
270270
cur.fetchone()
271271

272-
@with_tracebacks(OverflowError, name="func_overflowerror")
272+
@with_tracebacks(OverflowError, msg_regex="func_overflowerror")
273273
def test_func_overflow_error(self):
274274
cur = self.con.cursor()
275275
with self.assertRaises(sqlite.DataError):
@@ -389,7 +389,7 @@ def test_func_return_too_large_int(self):
389389
with self.assertRaisesRegex(sqlite.DataError, msg):
390390
cur.execute("select largeint()")
391391

392-
@with_tracebacks(UnicodeEncodeError, "surrogates not allowed", "chr")
392+
@with_tracebacks(UnicodeEncodeError, "surrogates not allowed")
393393
def test_func_return_text_with_surrogates(self):
394394
cur = self.con.cursor()
395395
self.con.create_function("pychr", 1, chr)
@@ -641,7 +641,7 @@ def test_aggr_error_on_create(self):
641641
with self.assertRaises(sqlite.OperationalError):
642642
self.con.create_function("bla", -100, AggrSum)
643643

644-
@with_tracebacks(AttributeError, name="AggrNoStep")
644+
@with_tracebacks(AttributeError, msg_regex="AggrNoStep")
645645
def test_aggr_no_step(self):
646646
cur = self.con.cursor()
647647
with self.assertRaises(sqlite.OperationalError) as cm:
@@ -656,23 +656,23 @@ def test_aggr_no_finalize(self):
656656
cur.execute("select nofinalize(t) from test")
657657
val = cur.fetchone()[0]
658658

659-
@with_tracebacks(ZeroDivisionError, name="AggrExceptionInInit")
659+
@with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInInit")
660660
def test_aggr_exception_in_init(self):
661661
cur = self.con.cursor()
662662
with self.assertRaises(sqlite.OperationalError) as cm:
663663
cur.execute("select excInit(t) from test")
664664
val = cur.fetchone()[0]
665665
self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error")
666666

667-
@with_tracebacks(ZeroDivisionError, name="AggrExceptionInStep")
667+
@with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInStep")
668668
def test_aggr_exception_in_step(self):
669669
cur = self.con.cursor()
670670
with self.assertRaises(sqlite.OperationalError) as cm:
671671
cur.execute("select excStep(t) from test")
672672
val = cur.fetchone()[0]
673673
self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error")
674674

675-
@with_tracebacks(ZeroDivisionError, name="AggrExceptionInFinalize")
675+
@with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInFinalize")
676676
def test_aggr_exception_in_finalize(self):
677677
cur = self.con.cursor()
678678
with self.assertRaises(sqlite.OperationalError) as cm:
@@ -822,11 +822,11 @@ def authorizer_cb(action, arg1, arg2, dbname, source):
822822
raise ValueError
823823
return sqlite.SQLITE_OK
824824

825-
@with_tracebacks(ValueError, name="authorizer_cb")
825+
@with_tracebacks(ValueError, msg_regex="authorizer_cb")
826826
def test_table_access(self):
827827
super().test_table_access()
828828

829-
@with_tracebacks(ValueError, name="authorizer_cb")
829+
@with_tracebacks(ValueError, msg_regex="authorizer_cb")
830830
def test_column_access(self):
831831
super().test_table_access()
832832

Lib/test/test_sqlite3/util.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@ def cx_limit(cx, category=sqlite3.SQLITE_LIMIT_SQL_LENGTH, limit=128):
2222
cx.setlimit(category, _prev)
2323

2424

25-
def with_tracebacks(exc, regex="", name=""):
25+
def with_tracebacks(exc, regex="", name="", msg_regex=""):
2626
"""Convenience decorator for testing callback tracebacks."""
2727
def decorator(func):
28-
_regex = re.compile(regex) if regex else None
28+
exc_regex = re.compile(regex) if regex else None
29+
_msg_regex = re.compile(msg_regex) if msg_regex else None
2930
@functools.wraps(func)
3031
def wrapper(self, *args, **kwargs):
3132
with test.support.catch_unraisable_exception() as cm:
3233
# First, run the test with traceback enabled.
33-
with check_tracebacks(self, cm, exc, _regex, name):
34+
with check_tracebacks(self, cm, exc, exc_regex, _msg_regex, name):
3435
func(self, *args, **kwargs)
3536

3637
# Then run the test with traceback disabled.
@@ -40,7 +41,7 @@ def wrapper(self, *args, **kwargs):
4041

4142

4243
@contextlib.contextmanager
43-
def check_tracebacks(self, cm, exc, regex, obj_name):
44+
def check_tracebacks(self, cm, exc, exc_regex, msg_regex, obj_name):
4445
"""Convenience context manager for testing callback tracebacks."""
4546
sqlite3.enable_callback_tracebacks(True)
4647
try:
@@ -49,9 +50,12 @@ def check_tracebacks(self, cm, exc, regex, obj_name):
4950
yield
5051

5152
self.assertEqual(cm.unraisable.exc_type, exc)
52-
if regex:
53+
if exc_regex:
5354
msg = str(cm.unraisable.exc_value)
54-
self.assertIsNotNone(regex.search(msg))
55+
self.assertIsNotNone(exc_regex.search(msg), (exc_regex, msg))
56+
if msg_regex:
57+
msg = cm.unraisable.err_msg
58+
self.assertIsNotNone(msg_regex.search(msg), (msg_regex, msg))
5559
if obj_name:
5660
self.assertEqual(cm.unraisable.object.__name__, obj_name)
5761
finally:

Lib/test/test_struct.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ def __del__(self):
694694
rc, stdout, stderr = assert_python_ok("-c", code)
695695
self.assertEqual(rc, 0)
696696
self.assertEqual(stdout.rstrip(), b"")
697-
self.assertIn(b"Exception ignored in:", stderr)
697+
self.assertIn(b"Exception ignored on calling deallocator", stderr)
698698
self.assertIn(b"C.__del__", stderr)
699699

700700
def test__struct_reference_cycle_cleaned_up(self):

Modules/_asynciomodule.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,8 @@ FutureObj_finalize(FutureObj *fut)
17151715
if (func != NULL) {
17161716
PyObject *res = PyObject_CallOneArg(func, context);
17171717
if (res == NULL) {
1718-
PyErr_WriteUnraisable(func);
1718+
PyErr_FormatUnraisable("Exception ignored on calling asyncio "
1719+
"function %R", func);
17191720
}
17201721
else {
17211722
Py_DECREF(res);
@@ -2978,7 +2979,8 @@ TaskObj_finalize(TaskObj *task)
29782979
if (func != NULL) {
29792980
PyObject *res = PyObject_CallOneArg(func, context);
29802981
if (res == NULL) {
2981-
PyErr_WriteUnraisable(func);
2982+
PyErr_FormatUnraisable("Exception ignored on calling asyncio "
2983+
"function %R", func);
29822984
}
29832985
else {
29842986
Py_DECREF(res);

Modules/_ctypes/_ctypes.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,8 @@ CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
463463
{
464464
StgInfo *info = _PyStgInfo_FromType_NoState(self);
465465
if (!info) {
466-
PyErr_WriteUnraisable(self);
466+
PyErr_FormatUnraisable("Exception ignored on calling ctypes %R "
467+
"traverse function", self);
467468
}
468469
if (info) {
469470
Py_VISIT(info->proto);
@@ -494,7 +495,7 @@ CType_Type_clear(PyObject *self)
494495
{
495496
StgInfo *info = _PyStgInfo_FromType_NoState(self);
496497
if (!info) {
497-
PyErr_WriteUnraisable(self);
498+
PyErr_FormatUnraisable("Exception ignored on clearing %R", self);
498499
}
499500
if (info) {
500501
ctype_clear_stginfo(info);
@@ -507,7 +508,7 @@ CType_Type_dealloc(PyObject *self)
507508
{
508509
StgInfo *info = _PyStgInfo_FromType_NoState(self);
509510
if (!info) {
510-
PyErr_WriteUnraisable(NULL); // NULL avoids segfault here
511+
PyErr_FormatUnraisable("Exception ignored on deallocating %R", self);
511512
}
512513
if (info) {
513514
PyMem_Free(info->ffi_type_pointer.elements);

Modules/_ctypes/callbacks.c

+22-23
Original file line numberDiff line numberDiff line change
@@ -494,32 +494,28 @@ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
494494

495495
func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject");
496496
if (!func) {
497-
PyErr_WriteUnraisable(context ? context : Py_None);
498497
/* There has been a warning before about this already */
499-
return E_FAIL;
498+
goto error;
500499
}
501500

502501
{
503502
PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid);
504503
if (py_rclsid == NULL) {
505504
Py_DECREF(func);
506-
PyErr_WriteUnraisable(context ? context : Py_None);
507-
return E_FAIL;
505+
goto error;
508506
}
509507
PyObject *py_riid = PyLong_FromVoidPtr((void *)riid);
510508
if (py_riid == NULL) {
511509
Py_DECREF(func);
512510
Py_DECREF(py_rclsid);
513-
PyErr_WriteUnraisable(context ? context : Py_None);
514-
return E_FAIL;
511+
goto error;
515512
}
516513
PyObject *py_ppv = PyLong_FromVoidPtr(ppv);
517514
if (py_ppv == NULL) {
518515
Py_DECREF(py_rclsid);
519516
Py_DECREF(py_riid);
520517
Py_DECREF(func);
521-
PyErr_WriteUnraisable(context ? context : Py_None);
522-
return E_FAIL;
518+
goto error;
523519
}
524520
result = PyObject_CallFunctionObjArgs(func,
525521
py_rclsid,
@@ -532,17 +528,21 @@ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
532528
}
533529
Py_DECREF(func);
534530
if (!result) {
535-
PyErr_WriteUnraisable(context ? context : Py_None);
536-
return E_FAIL;
531+
goto error;
537532
}
538533

539534
retval = PyLong_AsLong(result);
540535
if (PyErr_Occurred()) {
541-
PyErr_WriteUnraisable(context ? context : Py_None);
542-
retval = E_FAIL;
536+
Py_DECREF(result);
537+
goto error;
543538
}
544539
Py_DECREF(result);
545540
return retval;
541+
542+
error:
543+
PyErr_FormatUnraisable("Exception ignored on calling "
544+
"ctypes.DllGetClassObject");
545+
return E_FAIL;
546546
}
547547

548548
STDAPI DllGetClassObject(REFCLSID rclsid,
@@ -570,34 +570,33 @@ long Call_CanUnloadNow(void)
570570

571571
mod = PyImport_ImportModule("ctypes");
572572
if (!mod) {
573-
/* OutputDebugString("Could not import ctypes"); */
574-
/* We assume that this error can only occur when shutting
575-
down, so we silently ignore it */
576-
PyErr_Clear();
577-
return E_FAIL;
573+
goto error;
578574
}
579575
/* Other errors cannot be raised, but are printed to stderr */
580576
func = PyObject_GetAttrString(mod, "DllCanUnloadNow");
581577
Py_DECREF(mod);
582578
if (!func) {
583-
PyErr_WriteUnraisable(context ? context : Py_None);
584-
return E_FAIL;
579+
goto error;
585580
}
586581

587582
result = _PyObject_CallNoArgs(func);
588583
Py_DECREF(func);
589584
if (!result) {
590-
PyErr_WriteUnraisable(context ? context : Py_None);
591-
return E_FAIL;
585+
goto error;
592586
}
593587

594588
retval = PyLong_AsLong(result);
595589
if (PyErr_Occurred()) {
596-
PyErr_WriteUnraisable(context ? context : Py_None);
597-
retval = E_FAIL;
590+
Py_DECREF(result);
591+
goto error;
598592
}
599593
Py_DECREF(result);
600594
return retval;
595+
596+
error:
597+
PyErr_FormatUnraisable("Exception ignored on calling "
598+
"ctypes.DllCanUnloadNow");
599+
return E_FAIL;
601600
}
602601

603602
/*

Modules/_datetimemodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ clear_current_module(PyInterpreterState *interp, PyObject *expected)
226226
goto finally;
227227

228228
error:
229-
PyErr_WriteUnraisable(NULL);
229+
PyErr_FormatUnraisable("Exception ignored on clearing _datetime module");
230230

231231
finally:
232232
PyErr_SetRaisedException(exc);

Modules/_io/fileio.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,10 @@ fileio_dealloc_warn(PyObject *op, PyObject *source)
105105
PyObject *exc = PyErr_GetRaisedException();
106106
if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
107107
/* Spurious errors can appear at shutdown */
108-
if (PyErr_ExceptionMatches(PyExc_Warning))
109-
PyErr_WriteUnraisable((PyObject *) self);
108+
if (PyErr_ExceptionMatches(PyExc_Warning)) {
109+
PyErr_FormatUnraisable("Exception ignored on closing file %R",
110+
self);
111+
}
110112
}
111113
PyErr_SetRaisedException(exc);
112114
}

Modules/_io/iobase.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ iobase_finalize(PyObject *self)
314314
PyErr_Clear();
315315
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(close));
316316
if (res == NULL) {
317-
PyErr_WriteUnraisable(self);
317+
PyErr_FormatUnraisable("Exception ignored on closing %R", self);
318318
}
319319
else {
320320
Py_DECREF(res);

0 commit comments

Comments
 (0)