#!/usr/bin/env python3 """Guard _PyMem_DebugRawFree's C89 locals and NULL-safe evaluation order.""" import re import sys from pathlib import Path source = Path(sys.argv[1]).read_text() match = re.search( r"\n_PyMem_DebugRawFree\(void \*ctx, void \*p\)\s*\{(.*?)\n\}", source, re.S, ) assert match, "_PyMem_DebugRawFree definition not found" body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S) declarations = """ debug_alloc_api_t *api; uint8_t *q; size_t nbytes; """ assert body.split()[:len(declarations.split())] == declarations.split(), ( "_PyMem_DebugRawFree must declare api, q, and nbytes without initializers at function entry" ) # Preserve the NULL return before either initializer is evaluated, especially # the pointer subtraction, and retain all subsequent operations in order. expected = declarations + """ if (p == NULL) { return; } api = (debug_alloc_api_t *)ctx; q = (uint8_t *)p - 2*SST; _PyMem_DebugCheckAddress(__func__, api->api_id, p); nbytes = read_size_t(q); nbytes += PYMEM_DEBUG_EXTRA_BYTES; memset(q, PYMEM_DEADBYTE, nbytes); api->alloc.free(api->alloc.ctx, q); """ assert body.split() == expected.split(), ( "preserve _PyMem_DebugRawFree assignments after the NULL return and original operation order" ) print("obmalloc _PyMem_DebugRawFree entry declarations and NULL-safe operation order: PASS")