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

210 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""Guard pymalloc_pool_extend's C89 declaration and operation order."""
import re
import sys
from pathlib import Path
source = Path(sys.argv[1]).read_text()
match = re.search(
r"\npymalloc_pool_extend\(poolp pool, uint size\)\s*\{(.*?)\n\}",
source, re.S,
)
assert match, "pymalloc_pool_extend definition not found"
body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S)
assert body.split()[:2] == ["poolp", "next;"], (
"pymalloc_pool_extend must declare next without an initializer at function entry"
)
# The extension path returns before reading nextpool. Keep the full-pool
# unlink reads and writes in their original order.
expected = """
poolp next;
if (UNLIKELY(pool->nextoffset <= pool->maxnextoffset)) {
pool->freeblock = (block*)pool + pool->nextoffset;
pool->nextoffset += INDEX2SIZE(size);
*(block **)(pool->freeblock) = NULL;
return;
}
next = pool->nextpool;
pool = pool->prevpool;
next->prevpool = pool;
pool->nextpool = next;
"""
assert body.split() == expected.split(), (
"preserve pymalloc_pool_extend extension, early return, and unlink evaluation order"
)
print("obmalloc pymalloc_pool_extend C89 declaration and original operation order: PASS")
match = re.search(
r"\nallocate_from_new_pool\(uint size\)\s*\{(.*?)\n\}",
source, re.S,
)
assert match, "allocate_from_new_pool definition not found"
body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S)
assert body.split()[:2] == ["poolp", "pool;"], (
"allocate_from_new_pool must declare pool without an initializer at function entry"
)
assert body.split()[:6] == ["poolp", "pool;", "block", "*bp;", "poolp", "next;"], (
"allocate_from_new_pool must declare bp and next without initializers at function entry"
)
assert re.findall(r"\bblock\s+\*bp\s*;", body) == ["block *bp;"], (
"allocate_from_new_pool must declare bp exactly once"
)
assert re.findall(r"\bpoolp\s+next\b", body) == ["poolp next"], (
"allocate_from_new_pool must declare next exactly once"
)
# Keep the freepools read after arena creation and arena-list updates, and
# preserve all subsequent cached-pool, new-pool, and initialization branches.
# Keep next's usedpools read immediately before the frontlink writes.
expected = """
poolp pool;
block *bp;
poolp next;
if (UNLIKELY(usable_arenas == NULL)) {
#ifdef WITH_MEMORY_LIMITS
if (narenas_currently_allocated >= MAX_ARENAS) {
return NULL;
}
#endif
usable_arenas = new_arena();
if (usable_arenas == NULL) {
return NULL;
}
usable_arenas->nextarena = usable_arenas->prevarena = NULL;
assert(nfp2lasta[usable_arenas->nfreepools] == NULL);
nfp2lasta[usable_arenas->nfreepools] = usable_arenas;
}
assert(usable_arenas->address != 0);
assert(usable_arenas->nfreepools > 0);
if (nfp2lasta[usable_arenas->nfreepools] == usable_arenas) {
nfp2lasta[usable_arenas->nfreepools] = NULL;
}
if (usable_arenas->nfreepools > 1) {
assert(nfp2lasta[usable_arenas->nfreepools - 1] == NULL);
nfp2lasta[usable_arenas->nfreepools - 1] = usable_arenas;
}
pool = usable_arenas->freepools;
if (LIKELY(pool != NULL)) {
usable_arenas->freepools = pool->nextpool;
usable_arenas->nfreepools--;
if (UNLIKELY(usable_arenas->nfreepools == 0)) {
assert(usable_arenas->freepools == NULL);
assert(usable_arenas->nextarena == NULL ||
usable_arenas->nextarena->prevarena ==
usable_arenas);
usable_arenas = usable_arenas->nextarena;
if (usable_arenas != NULL) {
usable_arenas->prevarena = NULL;
assert(usable_arenas->address != 0);
}
}
else {
assert(usable_arenas->freepools != NULL ||
usable_arenas->pool_address <=
(block*)usable_arenas->address +
ARENA_SIZE - POOL_SIZE);
}
}
else {
assert(usable_arenas->nfreepools > 0);
assert(usable_arenas->freepools == NULL);
pool = (poolp)usable_arenas->pool_address;
assert((block*)pool <= (block*)usable_arenas->address +
ARENA_SIZE - POOL_SIZE);
pool->arenaindex = (uint)(usable_arenas - arenas);
assert(&arenas[pool->arenaindex] == usable_arenas);
pool->szidx = DUMMY_SIZE_IDX;
usable_arenas->pool_address += POOL_SIZE;
--usable_arenas->nfreepools;
if (usable_arenas->nfreepools == 0) {
assert(usable_arenas->nextarena == NULL ||
usable_arenas->nextarena->prevarena ==
usable_arenas);
usable_arenas = usable_arenas->nextarena;
if (usable_arenas != NULL) {
usable_arenas->prevarena = NULL;
assert(usable_arenas->address != 0);
}
}
}
next = usedpools[size + size];
pool->nextpool = next;
pool->prevpool = next;
next->nextpool = pool;
next->prevpool = pool;
pool->ref.count = 1;
if (pool->szidx == size) {
bp = pool->freeblock;
assert(bp != NULL);
pool->freeblock = *(block **)bp;
return bp;
}
pool->szidx = size;
size = INDEX2SIZE(size);
bp = (block *)pool + POOL_OVERHEAD;
pool->nextoffset = POOL_OVERHEAD + (size << 1);
pool->maxnextoffset = POOL_SIZE - size;
pool->freeblock = bp + size;
*(block **)(pool->freeblock) = NULL;
return bp;
"""
assert body.split() == expected.split(), (
"preserve allocate_from_new_pool arena updates, freepools assignment, and control-flow order"
)
print("obmalloc allocate_from_new_pool pool/bp/next declarations and original operation order: PASS")
match = re.search(
r"\npymalloc_alloc\(void \*ctx, size_t nbytes\)\s*\{(.*?)\n\}",
source, re.S,
)
assert match, "pymalloc_alloc definition not found"
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
assert body.split()[:6] == ["uint", "size;", "poolp", "pool;", "block", "*bp;"], (
"pymalloc_alloc must declare size, pool, and bp without initializers at function entry"
)
# Preserve the conditional Valgrind checks and request-size early returns before
# evaluating size and reading usedpools, plus the exact bp branch operations.
expected = """
uint size;
poolp pool;
block *bp;
#ifdef WITH_VALGRIND
if (UNLIKELY(running_on_valgrind == -1)) {
running_on_valgrind = RUNNING_ON_VALGRIND;
}
if (UNLIKELY(running_on_valgrind)) {
return NULL;
}
#endif
if (UNLIKELY(nbytes == 0)) {
return NULL;
}
if (UNLIKELY(nbytes > SMALL_REQUEST_THRESHOLD)) {
return NULL;
}
size = (uint)(nbytes - 1) >> ALIGNMENT_SHIFT;
pool = usedpools[size + size];
if (LIKELY(pool != pool->nextpool)) {
++pool->ref.count;
bp = pool->freeblock;
assert(bp != NULL);
if (UNLIKELY((pool->freeblock = *(block **)bp) == NULL)) {
pymalloc_pool_extend(pool, size);
}
}
else {
bp = allocate_from_new_pool(size);
}
return (void *)bp;
"""
assert body.split() == expected.split(), (
"preserve pymalloc_alloc early returns, size/pool evaluation, and bp control-flow order"
)
print("obmalloc pymalloc_alloc size/pool/bp declarations and original operation order: PASS")