86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Focused Visual C++ 6.0 C89 regression checks for object.c."""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
source = Path(sys.argv[1]).read_text()
|
|
|
|
|
|
def body(name):
|
|
found = re.search(re.escape(name) + r"\s*\([^;]*\)\s*\{(?P<body>.*?)\n\}", source, re.S)
|
|
assert found, name + " definition not found"
|
|
return found.group("body")
|
|
|
|
|
|
def check(name, tokens, message):
|
|
text = body(name)
|
|
positions = [text.find(token) for token in tokens]
|
|
assert all(position >= 0 for position in positions) and positions == sorted(positions), message
|
|
return text
|
|
|
|
|
|
text = check("PyObject_CallFinalizerFromDealloc", (
|
|
"Py_ssize_t refcnt;",
|
|
"if (Py_REFCNT(self) != 0)",
|
|
"refcnt = Py_REFCNT(self);",
|
|
"_Py_NewReference(self);",
|
|
"Py_SET_REFCNT(self, refcnt);",
|
|
), "PyObject_CallFinalizerFromDealloc must hoist refcnt while preserving resurrection order")
|
|
assert "Py_ssize_t refcnt =" not in text
|
|
print("object PyObject_CallFinalizerFromDealloc C89 local and refcount order: PASS")
|
|
|
|
text = check("_PyObject_Dump", (
|
|
"PyTypeObject *type;",
|
|
"PyGILState_STATE gil;",
|
|
"PyObject *error_type, *error_value, *error_traceback;",
|
|
"if (_PyObject_IsFreed(op))",
|
|
"type = Py_TYPE(op);",
|
|
"gil = PyGILState_Ensure();",
|
|
"PyErr_Fetch(&error_type, &error_value, &error_traceback);",
|
|
), "_PyObject_Dump must hoist locals without changing diagnostics or exception preservation")
|
|
assert "PyTypeObject *type =" not in text and "PyGILState_STATE gil =" not in text
|
|
print("object _PyObject_Dump C89 locals and exception preservation: PASS")
|
|
|
|
text = check("PyObject_Repr", (
|
|
"PyObject *res;",
|
|
"PyThreadState *tstate;",
|
|
"if (PyErr_CheckSignals())",
|
|
"tstate = _PyThreadState_GET();",
|
|
), "PyObject_Repr must hoist tstate while preserving signal-check order")
|
|
assert "PyThreadState *tstate =" not in text
|
|
print("object PyObject_Repr C89 local and signal-check order: PASS")
|
|
|
|
text = body("_PyObject_DictPointer")
|
|
expected = '''
|
|
Py_ssize_t dictoffset;
|
|
PyTypeObject *tp = Py_TYPE(obj);
|
|
|
|
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
|
return _PyObject_ManagedDictPointer(obj);
|
|
}
|
|
dictoffset = tp->tp_dictoffset;
|
|
if (dictoffset == 0)
|
|
return NULL;
|
|
if (dictoffset < 0) {
|
|
Py_ssize_t tsize = Py_SIZE(obj);
|
|
size_t size;
|
|
if (tsize < 0) {
|
|
tsize = -tsize;
|
|
}
|
|
size = _PyObject_VAR_SIZE(tp, tsize);
|
|
assert(size <= (size_t)PY_SSIZE_T_MAX);
|
|
dictoffset += (Py_ssize_t)size;
|
|
|
|
_PyObject_ASSERT(obj, dictoffset > 0);
|
|
_PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0);
|
|
}
|
|
return (PyObject **) ((char *)obj + dictoffset);
|
|
'''
|
|
assert text.split() == expected.split(), (
|
|
"_PyObject_DictPointer must hoist only size to the block's opening declarations "
|
|
"and preserve the size expression and statement order"
|
|
)
|
|
print("object _PyObject_DictPointer C89 size declaration and offset calculation order: PASS")
|