Files
Python3-Win9x/scripts/vc6-floatobject-pack4-c89.test.py

103 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Guard C89 local ordering in the float32 packing fallback."""
import sys
from pathlib import Path
from typing import NoReturn
def fail(message: str) -> NoReturn:
print(message, file=sys.stderr)
raise SystemExit(1)
def extract_function(source: str, signature: str) -> str:
start = source.find(signature)
if start < 0:
fail(f"missing function signature: {signature}")
brace = source.find("{", start + len(signature))
if brace < 0:
fail("missing function body")
depth = 0
for end in range(brace, len(source)):
if source[end] == "{":
depth += 1
elif source[end] == "}":
depth -= 1
if depth == 0:
return source[brace + 1:end]
fail("unterminated function body")
source = Path(sys.argv[1]).read_text(encoding="utf-8")
body = extract_function(source, "PyFloat_Pack4(double x, char *data, int le)")
expected = """ else {
unsigned char s[sizeof(float)];
float y = (float)x;
int i, incr = 1;"""
if expected not in body:
fail("float32 fallback locals must be declared at the start of its block")
copy = body.find("memcpy(s, &y, sizeof(float));")
infinity_check = body.find("if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x))")
pack_loop = body.find("for (i = 0; i < 4; i++)")
if min(copy, infinity_check, pack_loop) < 0 or not infinity_check < copy < pack_loop:
fail("float32 fallback must preserve overflow-check/copy/packing order")
dealloc = extract_function(source, "_PyFloat_ExactDealloc(PyObject *obj)")
if " PyFloatObject *op;" not in dealloc or " PyFloatObject *op =" in dealloc:
fail("float exact deallocator op must be declared without initializer at entry")
if " struct _Py_float_state *state;" not in dealloc or " struct _Py_float_state *state =" in dealloc:
fail("float exact deallocator state must be declared without initializer at entry")
if not dealloc.find("assert(PyFloat_CheckExact(obj));") < dealloc.find("op = (PyFloatObject *)obj;") < dealloc.find("state = get_float_state();"):
fail("float exact deallocator must preserve assert/op/state initialization order")
as_double = extract_function(source, "PyFloat_AsDouble(PyObject *op)")
if " PyObject *res;" not in as_double or " double val;" not in as_double:
fail("PyFloat_AsDouble temporaries must be declared at function entry")
if "PyObject *res = _PyNumber_Index(op);" in as_double or "double val = PyLong_AsDouble(res);" in as_double:
fail("PyFloat_AsDouble must not redeclare its entry temporaries")
if not as_double.find("res = _PyNumber_Index(op);") < as_double.find("val = PyLong_AsDouble(res);") < as_double.find("Py_DECREF(res);"):
fail("PyFloat_AsDouble must preserve index-convert/decref order")
vectorcall = extract_function(source, "float_vectorcall(PyObject *type, PyObject * const*args,")
for declaration in (" Py_ssize_t nargs;", " PyObject *x;"):
if declaration not in vectorcall:
fail("float_vectorcall locals must be declared at function entry")
if "Py_ssize_t nargs =" in vectorcall or "PyObject *x =" in vectorcall:
fail("float_vectorcall locals must not be initialized at declaration")
if not vectorcall.find("nargs = PyVectorcall_NARGS(nargsf);") < vectorcall.find("x = nargs >= 1 ? args[0] : NULL;"):
fail("float_vectorcall must preserve nargs-before-argument selection order")
type_init = extract_function(source, "PyTypeObject PyFloat_Type =")
expected_slots = """ float_new, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
0, /* tp_del */
0, /* tp_version_tag */
0, /* tp_finalize */
(vectorcallfunc)float_vectorcall, /* tp_vectorcall */"""
if expected_slots not in type_init or ".tp_vectorcall =" in type_init:
fail("PyFloat_Type vectorcall must use C89 positional trailing slots")
state_init = extract_function(source, "_PyFloat_InitState(PyInterpreterState *interp)")
format_declaration = " float_format_type detected_double_format, detected_float_format;"
if format_declaration not in state_init:
fail("float format detection locals must be declared at function entry")
if format_declaration in state_init[state_init.find("if (!_Py_IsMainInterpreter(interp))"):]:
fail("float format detection locals must not be declared after a statement")
clinic = Path(sys.argv[2]).read_text(encoding="utf-8")
wrapper = extract_function(clinic, "float___getformat__(PyTypeObject *type, PyObject *arg)")
declaration = " Py_ssize_t typestr_length;"
if declaration not in wrapper:
fail("float.__getformat__ typestr_length must be declared at wrapper entry")
validation = wrapper.find("if (!PyUnicode_Check(arg))")
assignment = wrapper.find("typestr = PyUnicode_AsUTF8AndSize(arg, &typestr_length);")
if validation < 0 or assignment < validation or "Py_ssize_t typestr_length;" in wrapper[validation:]:
fail("Clinic wrapper must preserve type validation before string conversion")
print("floatobject C89 declarations and generated Clinic validation order: PASS")