#!/usr/bin/env python3 """Check tuple_alloc's C89 declaration and validation/allocation order.""" import re import sys from pathlib import Path source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/tupleobject.c") match = re.search( r"static PyTupleObject \*\ntuple_alloc\(Py_ssize_t size\)\n\{(.*?)\n\}", source.read_text(), re.S, ) assert match, "tuple_alloc definition not found" body = match.group(1) assert re.match(r"\s*PyTupleObject \*op;", body), ( "tuple_alloc: op must be declared without initializer before the size check; " "declaration after statement is not C89 compatible" ) expected = """ PyTupleObject *op; if (size < 0) { PyErr_BadInternalCall(); return NULL; } #ifdef Py_DEBUG assert(size != 0); // The empty tuple is statically allocated. #endif op = maybe_freelist_pop(size); if (op == NULL) { /* Check for overflow */ if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) - sizeof(PyObject *))) / sizeof(PyObject *)) { return (PyTupleObject *)PyErr_NoMemory(); } op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); if (op == NULL) return NULL; } return op; """ assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), ( "preserve size validation, debug assertion, single freelist lookup, overflow " "check, GC allocation, error/return order, and absence of refcount operations" ) print("tuple_alloc C89 declaration and validation/allocation order: PASS")