#!/usr/bin/env python3 """Guard _PyObject_Calloc's C89 declarations and original operation order.""" import re import sys from pathlib import Path source = Path(sys.argv[1]).read_text() match = re.search( r"\n_PyObject_Calloc\(void \*ctx, size_t nelem, size_t elsize\)\s*\{(.*?)\n\}", source, re.S, ) assert match, "_PyObject_Calloc definition not found" body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S) assert body.split()[:4] == ["size_t", "nbytes;", "void*", "ptr;"], ( "_PyObject_Calloc must declare nbytes and ptr without initializers at function entry" ) # Keep multiplication after the overflow assertion, allocation after the size # calculation, and zeroing, fallback allocation, and accounting in their order. expected = """ size_t nbytes; void* ptr; assert(elsize == 0 || nelem <= (size_t)PY_SSIZE_T_MAX / elsize); nbytes = nelem * elsize; ptr = pymalloc_alloc(ctx, nbytes); if (LIKELY(ptr != NULL)) { memset(ptr, 0, nbytes); return ptr; } ptr = PyMem_RawCalloc(nelem, elsize); if (ptr != NULL) { raw_allocated_blocks++; } return ptr; """ assert body.split() == expected.split(), ( "preserve _PyObject_Calloc assertion, evaluation, zeroing, fallback, and accounting order" ) print("obmalloc _PyObject_Calloc nbytes/ptr entry declarations and original operation order: PASS")