Files
Python3-Win9x/scripts/vc6-obmalloc-debugrawrealloc-c89.test.py
T

127 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Guard _PyMem_DebugRawRealloc's C89 locals and complete operation order."""
import re
import sys
from pathlib import Path
source = Path(sys.argv[1]).read_text()
match = re.search(
r"\n_PyMem_DebugRawRealloc\(void \*ctx, void \*p, size_t nbytes\)\s*\{(.*?)\n\}",
source, re.S,
)
assert match, "_PyMem_DebugRawRealloc definition not found"
body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S)
declarations = """
debug_alloc_api_t *api;
uint8_t *head;
uint8_t *data;
uint8_t *r;
uint8_t *tail;
size_t total;
size_t original_nbytes;
#define ERASED_SIZE 64
uint8_t save[2*ERASED_SIZE];
#ifdef PYMEM_DEBUG_SERIALNO
size_t block_serialno;
#endif
"""
assert body.split()[:len(declarations.split())] == declarations.split(), (
"_PyMem_DebugRawRealloc must declare locals without initializers at function entry, "
"including block_serialno under PYMEM_DEBUG_SERIALNO"
)
# Keep the ctx cast after the NULL return and the serial-number read after
# the overflow guard and tail calculation. Freeze both preprocessor paths,
# allocation failure recovery, saved-byte restoration, and growth filling.
expected = declarations + """
if (p == NULL) {
return _PyMem_DebugRawAlloc(0, ctx, nbytes);
}
api = (debug_alloc_api_t *)ctx;
_PyMem_DebugCheckAddress(__func__, api->api_id, p);
data = (uint8_t *)p;
head = data - 2*SST;
original_nbytes = read_size_t(head);
if (nbytes > (size_t)PY_SSIZE_T_MAX - PYMEM_DEBUG_EXTRA_BYTES) {
return NULL;
}
total = nbytes + PYMEM_DEBUG_EXTRA_BYTES;
tail = data + original_nbytes;
#ifdef PYMEM_DEBUG_SERIALNO
block_serialno = read_size_t(tail + SST);
#endif
if (original_nbytes <= sizeof(save)) {
memcpy(save, data, original_nbytes);
memset(data - 2 * SST, PYMEM_DEADBYTE,
original_nbytes + PYMEM_DEBUG_EXTRA_BYTES);
}
else {
memcpy(save, data, ERASED_SIZE);
memset(head, PYMEM_DEADBYTE, ERASED_SIZE + 2 * SST);
memcpy(&save[ERASED_SIZE], tail - ERASED_SIZE, ERASED_SIZE);
memset(tail - ERASED_SIZE, PYMEM_DEADBYTE,
ERASED_SIZE + PYMEM_DEBUG_EXTRA_BYTES - 2 * SST);
}
r = (uint8_t *)api->alloc.realloc(api->alloc.ctx, head, total);
if (r == NULL) {
nbytes = original_nbytes;
}
else {
head = r;
#ifdef PYMEM_DEBUG_SERIALNO
bumpserialno();
block_serialno = serialno;
#endif
}
data = head + 2*SST;
write_size_t(head, nbytes);
head[SST] = (uint8_t)api->api_id;
memset(head + SST + 1, PYMEM_FORBIDDENBYTE, SST-1);
tail = data + nbytes;
memset(tail, PYMEM_FORBIDDENBYTE, SST);
#ifdef PYMEM_DEBUG_SERIALNO
write_size_t(tail + SST, block_serialno);
#endif
if (original_nbytes <= sizeof(save)) {
memcpy(data, save, Py_MIN(nbytes, original_nbytes));
}
else {
size_t i = original_nbytes - ERASED_SIZE;
memcpy(data, save, Py_MIN(nbytes, ERASED_SIZE));
if (nbytes > i) {
memcpy(data + i, &save[ERASED_SIZE],
Py_MIN(nbytes - i, ERASED_SIZE));
}
}
if (r == NULL) {
return NULL;
}
if (nbytes > original_nbytes) {
memset(data + original_nbytes, PYMEM_CLEANBYTE,
nbytes - original_nbytes);
}
return data;"""
assert body.split() == expected.split(), (
"preserve _PyMem_DebugRawRealloc initialization evaluation points, guards, "
"and complete operation/control-flow order"
)
print("obmalloc _PyMem_DebugRawRealloc C89 declarations and original operation order: PASS")