126 lines
4.1 KiB
Python
126 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Guard insert_to_freepool'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"\ninsert_to_freepool\(poolp pool\)\s*\{(.*?)\n\}",
|
|
source, re.S,
|
|
)
|
|
assert match, "insert_to_freepool definition not found"
|
|
body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S)
|
|
declarations = """
|
|
poolp next;
|
|
poolp prev;
|
|
struct arena_object *ao;
|
|
uint nf;
|
|
struct arena_object* lastnf;
|
|
struct arena_object* p;
|
|
"""
|
|
assert body.split()[:len(declarations.split())] == declarations.split(), (
|
|
"insert_to_freepool must declare all six locals without initializers at function entry"
|
|
)
|
|
|
|
# Assignments stay at the original evaluation points, including p inside its
|
|
# branch. Preserve every assertion, branch, return, and pointer update, as well
|
|
# as the radix-tree conditional, throughout all four arena-management cases.
|
|
expected = declarations + """
|
|
next = pool->nextpool;
|
|
prev = pool->prevpool;
|
|
next->prevpool = prev;
|
|
prev->nextpool = next;
|
|
ao = &arenas[pool->arenaindex];
|
|
pool->nextpool = ao->freepools;
|
|
ao->freepools = pool;
|
|
nf = ao->nfreepools;
|
|
lastnf = nfp2lasta[nf];
|
|
assert((nf == 0 && lastnf == NULL) ||
|
|
(nf > 0 &&
|
|
lastnf != NULL &&
|
|
lastnf->nfreepools == nf &&
|
|
(lastnf->nextarena == NULL ||
|
|
nf < lastnf->nextarena->nfreepools)));
|
|
if (lastnf == ao) {
|
|
p = ao->prevarena;
|
|
nfp2lasta[nf] = (p != NULL && p->nfreepools == nf) ? p : NULL;
|
|
}
|
|
ao->nfreepools = ++nf;
|
|
if (nf == ao->ntotalpools && ao->nextarena != NULL) {
|
|
assert(ao->prevarena == NULL ||
|
|
ao->prevarena->address != 0);
|
|
assert(ao ->nextarena == NULL ||
|
|
ao->nextarena->address != 0);
|
|
if (ao->prevarena == NULL) {
|
|
usable_arenas = ao->nextarena;
|
|
assert(usable_arenas == NULL ||
|
|
usable_arenas->address != 0);
|
|
}
|
|
else {
|
|
assert(ao->prevarena->nextarena == ao);
|
|
ao->prevarena->nextarena =
|
|
ao->nextarena;
|
|
}
|
|
if (ao->nextarena != NULL) {
|
|
assert(ao->nextarena->prevarena == ao);
|
|
ao->nextarena->prevarena =
|
|
ao->prevarena;
|
|
}
|
|
ao->nextarena = unused_arena_objects;
|
|
unused_arena_objects = ao;
|
|
#if WITH_PYMALLOC_RADIX_TREE
|
|
arena_map_mark_used(ao->address, 0);
|
|
#endif
|
|
_PyObject_Arena.free(_PyObject_Arena.ctx,
|
|
(void *)ao->address, ARENA_SIZE);
|
|
ao->address = 0;
|
|
--narenas_currently_allocated;
|
|
return;
|
|
}
|
|
if (nf == 1) {
|
|
ao->nextarena = usable_arenas;
|
|
ao->prevarena = NULL;
|
|
if (usable_arenas)
|
|
usable_arenas->prevarena = ao;
|
|
usable_arenas = ao;
|
|
assert(usable_arenas->address != 0);
|
|
if (nfp2lasta[1] == NULL) {
|
|
nfp2lasta[1] = ao;
|
|
}
|
|
return;
|
|
}
|
|
if (nfp2lasta[nf] == NULL) {
|
|
nfp2lasta[nf] = ao;
|
|
}
|
|
if (ao == lastnf) {
|
|
return;
|
|
}
|
|
assert(ao->nextarena != NULL);
|
|
if (ao->prevarena != NULL) {
|
|
assert(ao->prevarena->nextarena == ao);
|
|
ao->prevarena->nextarena = ao->nextarena;
|
|
}
|
|
else {
|
|
assert(usable_arenas == ao);
|
|
usable_arenas = ao->nextarena;
|
|
}
|
|
ao->nextarena->prevarena = ao->prevarena;
|
|
ao->prevarena = lastnf;
|
|
ao->nextarena = lastnf->nextarena;
|
|
if (ao->nextarena != NULL) {
|
|
ao->nextarena->prevarena = ao;
|
|
}
|
|
lastnf->nextarena = ao;
|
|
assert(ao->nextarena == NULL || nf <= ao->nextarena->nfreepools);
|
|
assert(ao->prevarena == NULL || nf > ao->prevarena->nfreepools);
|
|
assert(ao->nextarena == NULL || ao->nextarena->prevarena == ao);
|
|
assert((usable_arenas == ao && ao->prevarena == NULL)
|
|
|| ao->prevarena->nextarena == ao);
|
|
"""
|
|
assert body.split() == expected.split(), (
|
|
"preserve insert_to_freepool evaluation, assertion, control-flow, and pointer-update order"
|
|
)
|
|
print("obmalloc insert_to_freepool entry declarations and original operation order: PASS")
|