43 lines
1.6 KiB
Python
43 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Check object_set_class's C89 newto declaration and evaluation timing."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nstatic int\nobject_set_class\(PyObject \*self, PyObject \*value, "
|
|
r"void \*closure\)\n\{(.*?)\n\}", source, re.S,
|
|
)
|
|
assert match, "object_set_class definition missing"
|
|
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
|
|
assert re.match(
|
|
r"\s*PyTypeObject \*oldto = Py_TYPE\(self\);\s*PyTypeObject \*newto;\s*if",
|
|
body,
|
|
), "object_set_class: newto must be in the opening declaration block (C89)"
|
|
assert len(re.findall(r"\bPyTypeObject\s*\*\s*newto\b", body)) == 1, "declare newto exactly once"
|
|
assert len(re.findall(r"\bnewto\s*=(?!=)", body)) == 1, "assign newto exactly once"
|
|
expected = """
|
|
if (value == NULL) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"can't delete __class__ attribute");
|
|
return -1;
|
|
}
|
|
if (!PyType_Check(value)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"__class__ must be set to a class, not '%s' object",
|
|
Py_TYPE(value)->tp_name);
|
|
return -1;
|
|
}
|
|
newto = (PyTypeObject *)value;
|
|
|
|
if (PySys_Audit("object.__setattr__", "OsO",
|
|
self, "__class__", value) < 0) {
|
|
return -1;
|
|
}
|
|
"""
|
|
assert body[body.index("if (value == NULL)"):body.index("if (!(PyType_IsSubtype")].split() == expected.split(), (
|
|
"object_set_class: preserve rejection paths, cast after type validation, "
|
|
"and audit before compatibility checks"
|
|
)
|
|
print("object_set_class newto C89 declaration and evaluation timing: PASS")
|