Skip to content

Commit 7e7d7a7

Browse files
authored
[mypyc] Fix object finalization (#19749)
Fixes mypyc/mypyc#1127
1 parent 341d3cc commit 7e7d7a7

File tree

3 files changed

+20
-20
lines changed

3 files changed

+20
-20
lines changed

mypy/test/helpers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ def clean_up(a: list[str]) -> list[str]:
233233
for p in prefix, prefix.replace(os.sep, "/"):
234234
if p != "/" and p != "//" and p != "\\" and p != "\\\\":
235235
ss = ss.replace(p, "")
236+
# Replace memory address with zeros
237+
if "at 0x" in ss:
238+
ss = re.sub(r"(at 0x)\w+>", r"\g<1>000000000000>", ss)
236239
# Ignore spaces at end of line.
237240
ss = re.sub(" +$", "", ss)
238241
# Remove pwd from driver.py's path

mypyc/codegen/emitclass.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,21 @@ def generate_dealloc_for_class(
889889
emitter.emit_line(f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)")
890890
emitter.emit_line("{")
891891
if has_tp_finalize:
892-
emitter.emit_line("if (!PyObject_GC_IsFinalized((PyObject *)self)) {")
893-
emitter.emit_line("Py_TYPE(self)->tp_finalize((PyObject *)self);")
892+
emitter.emit_line("PyObject *type, *value, *traceback;")
893+
emitter.emit_line("PyErr_Fetch(&type, &value, &traceback);")
894+
emitter.emit_line("int res = PyObject_CallFinalizerFromDealloc((PyObject *)self);")
895+
# CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
896+
# However, the message is slightly different due to the way mypyc compiles classes.
897+
# CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
898+
# mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
899+
emitter.emit_line("if (PyErr_Occurred() != NULL) {")
900+
# Don't untrack instance if error occurred
901+
emitter.emit_line("PyErr_WriteUnraisable((PyObject *)self);")
902+
emitter.emit_line("res = -1;")
903+
emitter.emit_line("}")
904+
emitter.emit_line("PyErr_Restore(type, value, traceback);")
905+
emitter.emit_line("if (res < 0) {")
906+
emitter.emit_line("goto done;")
894907
emitter.emit_line("}")
895908
emitter.emit_line("PyObject_GC_UnTrack(self);")
896909
if cl.reuse_freed_instance:
@@ -900,6 +913,7 @@ def generate_dealloc_for_class(
900913
emitter.emit_line(f"{clear_func_name}(self);")
901914
emitter.emit_line("Py_TYPE(self)->tp_free((PyObject *)self);")
902915
emitter.emit_line("CPy_TRASHCAN_END(self)")
916+
emitter.emit_line("done: ;")
903917
emitter.emit_line("}")
904918

905919

@@ -930,30 +944,13 @@ def generate_finalize_for_class(
930944
emitter.emit_line("static void")
931945
emitter.emit_line(f"{finalize_func_name}(PyObject *self)")
932946
emitter.emit_line("{")
933-
emitter.emit_line("PyObject *type, *value, *traceback;")
934-
emitter.emit_line("PyErr_Fetch(&type, &value, &traceback);")
935947
emitter.emit_line(
936948
"{}{}{}(self);".format(
937949
emitter.get_group_prefix(del_method.decl),
938950
NATIVE_PREFIX,
939951
del_method.cname(emitter.names),
940952
)
941953
)
942-
emitter.emit_line("if (PyErr_Occurred() != NULL) {")
943-
emitter.emit_line('PyObject *del_str = PyUnicode_FromString("__del__");')
944-
emitter.emit_line(
945-
"PyObject *del_method = (del_str == NULL) ? NULL : _PyType_Lookup(Py_TYPE(self), del_str);"
946-
)
947-
# CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
948-
# However, the message is slightly different due to the way mypyc compiles classes.
949-
# CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
950-
# mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
951-
emitter.emit_line("PyErr_WriteUnraisable(del_method);")
952-
emitter.emit_line("Py_XDECREF(del_method);")
953-
emitter.emit_line("Py_XDECREF(del_str);")
954-
emitter.emit_line("}")
955-
# PyErr_Restore also clears exception raised in __del__.
956-
emitter.emit_line("PyErr_Restore(type, value, traceback);")
957954
emitter.emit_line("}")
958955

959956

mypyc/test-data/run-classes.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3110,7 +3110,7 @@ f = native.F()
31103110
del f
31113111

31123112
[out]
3113-
Exception ignored in: <slot wrapper '__del__' of 'F' objects>
3113+
Exception ignored in: <native.F object at 0x000000000000>
31143114
Traceback (most recent call last):
31153115
File "native.py", line 5, in __del__
31163116
raise Exception("e2")

0 commit comments

Comments
 (0)