Skip to content

Commit cf10f38

Browse files
rounds R16-R32: bug-hunt sweep + bench refresh
Squashed the R16–R32 branch-isolated reviewer loop. Each round ran six reviewers in parallel (allocators / containers / std-core / sys+parsers / tests+bench+fuzz / cross-cutting) on private git worktrees, then merged back into r16-base. Anti-skim framing from R24 onward turned up convention drift the earlier rounds missed; bug-hunt framing from R32 turned up real safety bugs. Highlights of substantive code work folded in: Stats accounting (R32-allocators) - bytes_in_use was bumped by user-requested at alloc but drawn down by the effective reservation (slot / page-rounded / padded bump) at free. Every alloc+free pair under-counted by the padding overhead; dealloc-side clamp-to-zero masked it. Heap / Page / Arena / Slab / Budget all updated to track effective bytes at alloc; XL mremap now adjusts by the page- count delta on kernel-resize. Parser safety (R32-sysparser) - Dns: VecPushBackR failure now deinits the partially-built DnsRecord instead of leaking name/target/rdata Strs. - JSON: signed-overflow UB in JReadNumber's negate path (would have fired on a future ZstrToI64 returning INT64_MIN). - Pdb: three u32 wraps on attacker sizes (div_ceil_u32, walk_publics cursor, load_section_table allocation). - Pe: pe_decode_optional was writing u32 through a u64*, tripping strict aliasing and yielding the wrong half on BE. Std-core parser safety (R32-stdcore) - read_chars_internal: OOB read on truncated `\xNN` input. - ZstrProcessEscape: same shape on the quoted-string decoder used by the JSON-style readers. - ZstrToF64: signed-overflow UB in the exponent loop on attacker-controlled digit count. Container safety (R32-containers) - StrToF64: signed-overflow UB in the exponent loop (mirrors the Zstr fix above). - list_sort: allocation-size overflow + downstream OOB memcpy on long lists. - remove_range_list / BitVecRemoveRange / BitVecContainsAt: additive overflow in bounds checks. - map_set_only: payload leak when the re-insert hit the probe budget — temp_entry holds deep-copied keys/values that now get key_copy_deinit / value_copy_deinit on failure. Build-config bugs (R31 + R32 crosscut) - meson.build evaluated `opt_map = ... or opt_alloc_debug` before the `opt_alloc_debug = opt_alloc_debug and opt_sys_backtrace` clip — so `map` could auto-enable from an already-clipped `alloc_debug`. Same ordering bug bit sys_dns vs parser_dns; both reordered. - Tests/Dwarf.Stripped raced against objcopy via missing meson `depends:`. - Std/Log.c LogWrite FATAL path called CaptureStackTrace unconditionally, breaking `-Dsys_backtrace=false`. Gated and the Backtrace.h include moved behind the same flag. Fuzz harness memory safety (R31 testsbench, ASan-confirmed) - VecCharPtr push/insert/merge paths leaked the caller's malloc'd Zstr (char_ptr_copy_init ZstrDup's into the vec's allocator). - VecCharPtr RESIZE-grow-fill assigned malloc'd ptrs directly into Vec slots, leaving heap_allocator_deallocate to see a foreign pointer on FuzzState teardown. - VecStr VecInitClone double-freed: copy_init=NULL fell back to MemCopy, aliasing Str.data between source and dest slots. Convention sweeps (R16–R30, plus R24–R30 anti-skim) - Public docs no longer name private snake_case backends or private headers (os_page_*, test_abort_handler, prng_internal, etc.). - Libc vocabulary in comments, error messages, and design prose reframed in in-tree vocabulary (strlen → ZstrLen, memcpy → MemCopy, "libc strtoll" → in-tree, dropped "no libc backtrace()" framing in Backtrace.h, etc.). - SUCCESS/FAILURE doc blocks added to every public macro and function that wasn't an exempt single-field accessor; Debug.h alone had 6 missing. - Container key types ship canonical `*_hash` (`const void *, u32`) and `*_compare` (`const void *, const void *`) shapes; added `bitvec_compare` to complete the set. - Iter / StrIter direct-field reads converted to public accessor macros across Parsers/* and Tests/Std/*. - Cross-namespace `.data` / `.length` / `.allocator` reaches replaced with the corresponding `*Begin` / `*Len` / `*Allocator` macros; new accessors added where none existed (ElfBuf, MachoBuf, BitVecAllocator, IntAllocator, FloatAllocator, PeCodeView, PdbInfoStream, MachoUuid). - `(void)0, ptr->field` lvalue-rejecting macro shape adopted throughout the accessor surface; deleted the function-shaped *GetAllocator getters. - `_Generic` arms inlined at every site (no helper wrappers that hide the dispatch); typed allocator entry points stop taking `Allocator *` and casting. - `BENCHMARK_FILTERS` doc and Heap.c's class-layout note rewritten in present-tense; "what we used to do" history narratives removed. - 7 deadweight Graph alias-wrapper macros deleted; bodies promoted to PascalCase first-class functions. - Naked-asm SetJmp/LongJmp in Tests/Util/TestRunner.c — fixes the STATUS_BAD_STACK on clang-cl + UCRT for deadend tests. - Heap XL slot lookup rewritten from sorted-array + bsearch + memmove to an open-addressed hash table; Heap XL realloc grows in place via the Linux direct-syscall mremap path with MREMAP_MAYMOVE. - HeapAllocator stats moved onto `base.stats` so the typed and dyn paths can't disagree; `Allocator` carries an inline `footprint_bytes` counter updated by the internal page-map shim. - Stack-init API surface (`StrInitStack`, `VecInitStack`, `BufInitStack`, …) carries the documented stack-init carve-out from CODING-CONVENTIONS.md. Bench harness - Bench-Perf/ dropped; Benchmark/ already covers it. - Bench tier split: heap_validate_full=true vs false reported side-by-side so the safety overhead is visible. - misra-arena reports n/a for backends that have no bulk reset; the bench harness no longer pretends a per-pointer free is a reset. Tests: 104/104 on local Linux (Nix gcc 15.2), 99/99 on Mac SSH (arm64 Apple clang). Full suite green under `-Db_sanitize=address,undefined` as well. Bench refreshed in Benchmark/README.md with 10 reps per backend.
1 parent 8f10bed commit cf10f38

170 files changed

Lines changed: 4634 additions & 3949 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Benchmark/README.md

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ Single alloc/free pair, 16 B:
1010

1111
| backend | time |
1212
|---|---:|
13-
| tcmalloc | 3.4 ns |
14-
| glibc | 7.2 ns |
15-
| jemalloc | 3.4 ns |
16-
| mimalloc | 2.9 ns |
17-
| misra (Heap, validate-full) | 13.4 ns |
18-
| misra (Heap, validate-fast) | 13.0 ns |
19-
| misra-correct (Slab, validate-full) | 12.8 ns |
20-
| misra-correct (Slab, validate-fast) | 8.8 ns |
13+
| tcmalloc | 3.7 ns |
14+
| glibc | 7.7 ns |
15+
| jemalloc | 10.8 ns |
16+
| mimalloc | 3.8 ns |
17+
| misra (Heap, validate-full) | 15.0 ns |
18+
| misra (Heap, validate-fast) | 14.2 ns |
19+
| misra-correct (Slab, validate-full) | 14.2 ns |
20+
| misra-correct (Slab, validate-fast) | 8.7 ns |
2121

2222
## Timing
2323

@@ -27,13 +27,13 @@ One `alloc(size)` immediately followed by `free(ptr)`, repeated. Hot reuse — t
2727

2828
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
2929
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
30-
| 16 B | 7.2 | 3.4 | 2.9 | 3.4 | 13.4 | 13.0 | 12.8 | 8.8 | 9.9 | n/a |
31-
| 64 B | 7.0 | 3.5 | 3.0 | 3.3 | 13.5 | 13.3 | 12.7 | 8.7 | 9.9 | n/a |
32-
| 256 B | 7.2 | 3.9 | 13.5 | 3.3 | 13.7 | 13.3 | 12.7 | 8.7 | 9.9 | n/a |
33-
| 1 KiB | 7.2 | 5.2 | 14.8 | 3.3 | 13.2 | 13.2 | 12.7 | 8.7 | 9.9 | n/a |
34-
| 4 KiB | 22.9 | 9.7 | 10.6 | 3.3 | 1514.5 | 1517.9 | 12.7 | 8.7 | 9.9 | 16.6 |
35-
| 16 KiB | 23.4 | 18.7 | 19.9 | 3.4 | 1159.8 | 1152.9 | 16.9 | 16.9 | 9.9 | 16.7 |
36-
| 64 KiB | 25.6 | 270.3 | 20.0 | 3.4 | 1529.7 | 1531.6 | 16.9 | 16.9 | 9.9 | 16.8 |
30+
| 16 B | 7.7 | 10.8 | 3.8 | 3.7 | 15.0 | 14.2 | 14.2 | 8.7 | 11.8 | n/a |
31+
| 64 B | 7.5 | 11.1 | 3.8 | 3.8 | 15.5 | 14.8 | 14.1 | 8.7 | 11.7 | n/a |
32+
| 256 B | 7.5 | 11.4 | 16.7 | 3.9 | 15.2 | 14.9 | 14.0 | 8.7 | 11.7 | n/a |
33+
| 1 KiB | 19.7 | 12.4 | 17.4 | 3.8 | 14.6 | 14.6 | 13.9 | 8.6 | 11.7 | n/a |
34+
| 4 KiB | 15.5 | 16.6 | 13.1 | 4.1 | 1185.1 | 1155.4 | 13.8 | 8.6 | 11.6 | 18.5 |
35+
| 16 KiB | 16.1 | 38.7 | 23.1 | 4.0 | 1185.6 | 1162.7 | 19.0 | 19.0 | 11.6 | 18.4 |
36+
| 64 KiB | 17.5 | 531.4 | 22.1 | 4.2 | 1193.6 | 1164.4 | 19.0 | 18.9 | 11.7 | 18.3 |
3737

3838
_Values in ns._
3939

@@ -43,9 +43,9 @@ _Values in ns._
4343

4444
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
4545
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
46-
| 128 × 64 B | 1.2 | 1.0 | 0.5 | 0.5 | 1.5 | 1.4 | 1.7 | 1.0 | n/a | n/a |
47-
| 1024 × 64 B | 9.6 | 10.9 | 4.0 | 4.3 | 11.8 | 11.7 | 17.5 | 12.2 | n/a | n/a |
48-
| 8192 × 64 B | 77.9 | 88.9 | 34.3 | 39.1 | 94.7 | 94.6 | 390.2 | 358.8 | n/a | n/a |
46+
| 128 × 64 B | 1.4 | 1.3 | 0.5 | 0.5 | 1.6 | 1.6 | 1.8 | 1.2 | n/a | n/a |
47+
| 1024 × 64 B | 11.2 | 24.9 | 4.2 | 4.3 | 13.0 | 12.8 | 18.8 | 15.4 | n/a | n/a |
48+
| 8192 × 64 B | 87.9 | 109.1 | 37.9 | 43.6 | 104.9 | 101.2 | 401.1 | 375.0 | n/a | n/a |
4949

5050
_Values in us._
5151

@@ -55,9 +55,9 @@ Same shape as the pair test but writes every byte of the allocation before freei
5555

5656
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
5757
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
58-
| 64 B | 7.0 | 4.3 | 3.3 | 4.1 | 14.4 | 14.3 | 14.4 | 9.9 | 10.7 | n/a |
59-
| 4 KiB | 33.0 | 23.1 | 24.1 | 18.8 | 2348.6 | 2364.9 | 30.9 | 25.0 | 56.3 | 33.7 |
60-
| 64 KiB | 864.7 | 1063.5 | 865.2 | 839.8 | 13202.5 | 13183.3 | 847.7 | 847.2 | 949.9 | 847.0 |
58+
| 64 B | 8.1 | 5.6 | 3.5 | 4.6 | 15.5 | 15.2 | 16.7 | 11.0 | 13.8 | n/a |
59+
| 4 KiB | 41.4 | 29.6 | 27.7 | 21.8 | 2389.9 | 2375.9 | 33.8 | 28.3 | 54.3 | 38.4 |
60+
| 64 KiB | 1290.2 | 1285.7 | 1001.9 | 977.8 | 13254.3 | 13046.3 | 848.2 | 849.2 | 915.5 | 848.8 |
6161

6262
_Values in ns._
6363

@@ -67,7 +67,7 @@ _Values in ns._
6767

6868
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
6969
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
70-
| Pareto(1.16, 24) | 28.6 | 10.9 | 11.3 | 11.1 | 32.5 | 32.6 | 32.2 | 31.8 | n/a | n/a |
70+
| Pareto(1.16, 24) | 30.3 | 15.1 | 12.8 | 12.6 | 32.8 | 32.1 | 32.9 | 33.8 | n/a | n/a |
7171

7272
_Values in us._
7373

@@ -77,7 +77,7 @@ Geometric realloc ladder from 8 B up to 1 MiB. Time per full ladder, lower is be
7777

7878
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
7979
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
80-
| 8 B → 1 MiB | 8265.9 | 4054.7 | 18185.7 | 15349.6 | 15787.3 | 16312.1 | 16030.5 | 16180.3 | 88.3 | n/a |
80+
| 8 B → 1 MiB | 5740.1 | 5188.4 | 22553.0 | 18382.7 | 17088.7 | 17618.5 | 16174.7 | 16072.4 | 126.0 | n/a |
8181

8282
_Values in ns._
8383

@@ -87,9 +87,9 @@ Allocate N small (32 B) objects, then release them all. Arena does this as one O
8787

8888
| benchmark | glibc | jemalloc | mimalloc | tcmalloc | misra-full | misra-fast | misra-correct-full | misra-correct-fast | misra-arena | misra-page |
8989
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
90-
| 128 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 0.6 | n/a |
91-
| 1024 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 4.9 | n/a |
92-
| 8192 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 39.5 | n/a |
90+
| 128 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 0.8 | n/a |
91+
| 1024 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 6.2 | n/a |
92+
| 8192 × 32 B | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | 49.4 | n/a |
9393

9494
_Values in us._
9595

@@ -99,11 +99,11 @@ Each allocator's own introspection API reports committed bytes after the workloa
9999

100100
| benchmark | live MB | glibc MB | jemalloc MB | mimalloc MB | tcmalloc MB | misra-full MB | misra-fast MB | misra-correct-full MB | misra-correct-fast MB | misra-arena MB | misra-page MB |
101101
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
102-
| Checkerboard (4 K small) | 0.6 | 1.1 | 9.2 | n/a | 2.0 | 0.6 | 0.6 | n/a | n/a | n/a | n/a |
103-
| Checkerboard (16 K small) | 2.5 | 3.9 | 11.8 | n/a | 4.0 | 2.5 | 2.5 | n/a | n/a | n/a | n/a |
104-
| Checkerboard (64 K small) | 10.0 | 15.1 | 21.8 | n/a | 14.0 | 10.0 | 10.0 | n/a | n/a | n/a | n/a |
105-
| Lifetime mix | 4.0 | 4.9 | 20.2 | n/a | 14.0 | 4.0 | 4.0 | n/a | n/a | n/a | n/a |
106-
| Page overhang | 18.2 | 20.3 | 32.4 | n/a | 27.0 | 18.2 | 18.2 | n/a | n/a | n/a | n/a |
102+
| Checkerboard (4 K small) | 0.6 | 2.1 | 9.1 | n/a | 7.0 | 0.8 | 0.8 | 0.8 | 0.8 | n/a | n/a |
103+
| Checkerboard (16 K small) | 2.5 | 4.1 | 11.9 | n/a | 7.0 | 3.2 | 3.2 | 3.1 | 3.1 | n/a | n/a |
104+
| Checkerboard (64 K small) | 10.0 | 15.3 | 21.8 | n/a | 16.0 | 12.6 | 12.6 | 12.5 | 12.5 | n/a | n/a |
105+
| Lifetime mix | 4.0 | 5.1 | 16.7 | n/a | 16.0 | 12.6 | 12.6 | 12.5 | 12.5 | n/a | n/a |
106+
| Page overhang | 18.2 | 20.4 | 32.3 | n/a | 29.0 | 34.3 | 34.3 | 34.2 | 34.2 | n/a | n/a |
107107

108108
## How to read
109109

@@ -143,10 +143,10 @@ Regenerates this file with measurements from the host.
143143

144144
| | |
145145
|---|---|
146-
| timestamp | 2026-05-29 02:14:47 UTC |
147-
| git rev | af143d4679e6 (master) |
146+
| timestamp | 2026-05-29 07:31:28 UTC |
147+
| git rev | ac3e23856006 (r16-base) |
148148
| host CPU | Intel(R) Core(TM) Ultra 7 165U |
149149
| kernel | Linux 6.18.28 |
150150
| compiler | gcc 14.3.0 |
151-
| build | validate-full: buildtype=release optimization=3 b_lto=True b_sanitize=[] alloc_debug=False heap_validate_full=True | validate-fast: buildtype=release optimization=3 b_lto=True b_sanitize=[] alloc_debug=False heap_validate_full=False |
151+
| build | validate-full: buildtype=release optimization=3 b_lto=False b_sanitize=[] alloc_debug=True heap_validate_full=True | validate-fast: buildtype=release optimization=3 b_sanitize=[] b_lto=False alloc_debug=True heap_validate_full=False |
152152
| reps | 10 per row (median reported) |

Benchmark/Source/Allocator.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ uint64_t bench_live_bytes(void);
9494
// * jemalloc: mallctl("stats.mapped")
9595
// * mimalloc: mi_process_info(&current_commit, ...)
9696
// * tcmalloc: MallocExtension_GetNumericProperty("generic.heap_size")
97-
// * misra: sum of PageAllocator.entries[i].bytes
97+
// * misra: AllocatorFootprintBytes(a) -- direct read of
98+
// base.footprint_bytes, which every typed allocator's
99+
// os_page_map/unmap pair maintains.
98100
//
99101
// (footprint - live) / footprint is the fragmentation ratio.
100102
uint64_t bench_footprint_bytes(void);

Benchmark/Source/Allocator_misra.c

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@
2323
#include <Misra/Std/Allocator/Heap.h>
2424
#include <Misra/Std/Allocator/Page.h>
2525

26-
static HeapAllocator g_heap;
27-
static Allocator *g_alloc = NULL;
28-
// `g_heap_typed` exists so the bench passes a typed `HeapAllocator *`
29-
// to AllocatorAlloc / AllocatorFree. With the perf-branch _Generic
30-
// macros that picks the typed-direct path (heap_allocator_allocate /
31-
// heap_allocator_free), skipping AllocatorAlloc_dyn + ValidateAllocator
32-
// + the retry loop + stats accounting. Without the macros (stock
33-
// build) it's just an unused alias.
26+
// Typed HeapAllocator pointer so AllocatorAlloc / AllocatorFree's
27+
// _Generic dispatches to the typed-direct path
28+
// (heap_allocator_allocate / heap_allocator_free), skipping
29+
// AllocatorAlloc_dyn + ValidateAllocator + the retry loop + stats
30+
// accounting. Stays NULL between bench_teardown and the next
31+
// bench_init so callers can branch on liveness.
32+
static HeapAllocator g_heap;
3433
static HeapAllocator *g_heap_typed = NULL;
3534

3635
Zstr bench_backend_name(void) {
@@ -47,7 +46,6 @@ Zstr bench_backend_name(void) {
4746

4847
void bench_init(void) {
4948
g_heap = HeapAllocatorInit();
50-
g_alloc = ALLOCATOR_OF(&g_heap);
5149
g_heap_typed = &g_heap;
5250
}
5351

@@ -57,15 +55,18 @@ void bench_init(void) {
5755
// honest pick. The hints exist so the bench code is uniform; this
5856
// backend deliberately ignores them, which is the whole point of
5957
// the comparison against Allocator_misra_correct.c.
60-
void bench_use_fixed_size(size_t slot) { (void)slot; }
61-
void bench_use_general(void) {}
62-
int bench_can_reset(void) { return 0; }
63-
void bench_reset(void) {}
58+
void bench_use_fixed_size(size_t slot) {
59+
(void)slot;
60+
}
61+
void bench_use_general(void) {}
62+
int bench_can_reset(void) {
63+
return 0;
64+
}
65+
void bench_reset(void) {}
6466

6567
void bench_teardown(void) {
66-
if (g_alloc) {
68+
if (g_heap_typed) {
6769
HeapAllocatorDeinit(&g_heap);
68-
g_alloc = NULL;
6970
g_heap_typed = NULL;
7071
}
7172
}
@@ -92,21 +93,19 @@ void bench_free(void *p) {
9293

9394
uint64_t bench_live_bytes(void) {
9495
#if FEATURE_ALLOC_STATS
95-
return (uint64_t)AllocatorBytesInUse(g_alloc);
96+
if (!g_heap_typed)
97+
return 0;
98+
return (uint64_t)AllocatorBytesInUse(g_heap_typed);
9699
#else
97100
return 0;
98101
#endif
99102
}
100103

101104
uint64_t bench_footprint_bytes(void) {
102-
// The HeapAllocator no longer embeds a PageAllocator -- it goes
103-
// straight to the kernel via the internal `_Os.h` shim and tracks
104-
// its OS-page descriptors in its own `pages[]` hash table plus
105-
// `xl[]` passthrough array. Those descriptors are not part of the
106-
// public surface, so there's no allocator-introspective accessor
107-
// we can call here without reaching into private fields. Fall back
108-
// to the stats-tracked live-bytes number, which underestimates
109-
// kernel footprint (no per-page overhead) but is the cleanest
110-
// public-API readout available.
111-
return bench_live_bytes();
105+
// HeapAllocator's `base.footprint_bytes` is bumped/drawn down by
106+
// every `os_page_map` / `os_page_unmap` call the heap issues, so
107+
// the direct-field accessor returns the exact OS-page footprint.
108+
if (!g_heap_typed)
109+
return 0;
110+
return (uint64_t)AllocatorFootprintBytes(g_heap_typed);
112111
}

Benchmark/Source/Allocator_misra_arena.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ uint64_t bench_live_bytes(void) {
9696
}
9797

9898
uint64_t bench_footprint_bytes(void) {
99-
// ArenaAllocator no longer embeds a PageAllocator; it talks directly
100-
// to the kernel via the internal `_Os.h` shim and tracks chunks
101-
// privately. Fall back to live-bytes from stats (undercounts the
102-
// per-chunk header overhead, but the only public-API readout).
103-
return bench_live_bytes();
99+
// ArenaAllocator talks directly to the kernel via the internal
100+
// `_Os.h` shim, and every `os_page_map` / `os_page_unmap` bumps
101+
// / draws down `base.footprint_bytes` on the owner allocator
102+
// it was handed. So the direct-field accessor on the live arena
103+
// is the exact OS-page footprint, no estimation.
104+
if (!g_arena_live) return 0;
105+
return (uint64_t)AllocatorFootprintBytes(&g_arena);
104106
}

Benchmark/Source/Allocator_misra_correct.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,8 @@ uint64_t bench_live_bytes(void) {
154154
}
155155

156156
uint64_t bench_footprint_bytes(void) {
157-
// Only the page-backed mode can report a meaningful footprint
158-
// today; Heap and Slab manage their own pages with no public
159-
// committed-bytes accessor yet.
160-
if (g_mode == MODE_PAGE) {
161-
return (uint64_t)PageAllocatorFootprintBytes(&g_page);
162-
}
157+
if (g_mode == MODE_HEAP) return (uint64_t)AllocatorFootprintBytes(&g_heap);
158+
if (g_mode == MODE_SLAB) return (uint64_t)AllocatorFootprintBytes(&g_slab);
159+
if (g_mode == MODE_PAGE) return (uint64_t)AllocatorFootprintBytes(&g_page);
163160
return 0;
164161
}

Benchmark/Source/Allocator_misra_page.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@ uint64_t bench_live_bytes(void) {
8080

8181
uint64_t bench_footprint_bytes(void) {
8282
if (!g_page_live) return 0;
83-
return (uint64_t)PageAllocatorFootprintBytes(&g_page);
83+
return (uint64_t)AllocatorFootprintBytes(&g_page);
8484
}

Benchmark/Source/Bench.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// 5. alloc + write every byte (alloc cost vs zero-touch cost)
99
//
1010
// Each runs once per binary; the binary itself picks the backend at
11-
// link time. The runner script (Scripts/run.sh) executes one binary per
11+
// link time. The runner script (Scripts/run.py) executes one binary per
1212
// allocator and concatenates the JSON output.
1313

1414
#include "Allocator.h"

0 commit comments

Comments
 (0)