Files
Python3-Win9x/scripts/vc6-typeobject-subtype-dealloc-gc-type-needs-decref-c89.test.py
T

104 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""Keep GC subtype_dealloc's decref decision C89-safe at its evaluation point."""
import re
import sys
from pathlib import Path
source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/typeobject.c").read_text()
match = re.search(
r"\nstatic void\nsubtype_dealloc\(PyObject \*self\)\n\{(.*?)\n\}",
source,
re.S,
)
assert match, "subtype_dealloc definition missing"
body = match.group(1)
assert re.match(
r"\s*PyTypeObject \*type, \*base;\s*destructor basedealloc;"
r"\s*int has_finalizer;\s*int type_needs_decref;",
body,
), "GC subtype_dealloc: type_needs_decref must be declared at function entry (C89)"
start = body.index(" /* We get here only if the type has GC */")
end = body.index(" /* Explanation of the weirdness", start)
branch = re.sub(r"/\*.*?\*/|//[^\n]*", "", body[start:end], flags=re.S)
expected = r"""
PyObject_GC_UnTrack(self);
Py_TRASHCAN_BEGIN(self, subtype_dealloc);
base = type;
while (( base->tp_dealloc) == subtype_dealloc) {
base = base->tp_base;
assert(base);
}
has_finalizer = type->tp_finalize || type->tp_del;
if (type->tp_finalize) {
_PyObject_GC_TRACK(self);
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
goto endlabel;
}
_PyObject_GC_UNTRACK(self);
}
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
PyObject_ClearWeakRefs(self);
}
if (type->tp_del) {
_PyObject_GC_TRACK(self);
type->tp_del(self);
if (Py_REFCNT(self) > 0) {
goto endlabel;
}
_PyObject_GC_UNTRACK(self);
}
if (has_finalizer) {
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
PyWeakReference **list = (PyWeakReference **) \
_PyObject_GET_WEAKREFS_LISTPTR(self);
while (*list)
_PyWeakref_ClearRef(*list);
}
}
base = type;
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
if (Py_SIZE(base))
clear_slots(base, self);
base = base->tp_base;
assert(base);
}
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
PyObject **dictptr = _PyObject_ManagedDictPointer(self);
if (*dictptr != NULL) {
assert(*_PyObject_ValuesPointer(self) == NULL);
Py_DECREF(*dictptr);
*dictptr = NULL;
}
else {
_PyObject_FreeInstanceAttributes(self);
}
}
else if (type->tp_dictoffset && !base->tp_dictoffset) {
PyObject **dictptr = _PyObject_DictPointer(self);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
if (dict != NULL) {
Py_DECREF(dict);
*dictptr = NULL;
}
}
}
type = Py_TYPE(self);
if (_PyType_IS_GC(base)) {
_PyObject_GC_TRACK(self);
}
type_needs_decref = (type->tp_flags & Py_TPFLAGS_HEAPTYPE
&& !(base->tp_flags & Py_TPFLAGS_HEAPTYPE));
assert(basedealloc);
basedealloc(self);
if (type_needs_decref) {
Py_DECREF(type);
}
endlabel:
Py_TRASHCAN_END
"""
assert branch.split() == expected.split(), (
"GC subtype_dealloc: preserve assignment evaluation point and all control flow"
)
print("GC subtype_dealloc type_needs_decref C89 declaration and unchanged control flow: PASS")