Skip to content

verify(oci): record the EXTENT half — .bss was invisible, not just relocs missing - #353

Merged
avrabe merged 1 commit into
mainfrom
verify/oci-p05-extent-evidence
Aug 13, 2026
Merged

verify(oci): record the EXTENT half — .bss was invisible, not just relocs missing#353
avrabe merged 1 commit into
mainfrom
verify/oci-p05-extent-evidence

Conversation

@avrabe

@avrabe avrabe commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Verify-Filter: (has-tag "oci")

Follow-up to #352. Code-free — records what measuring meld's question turned up, which is larger than the relocation gap it started from.

meld asked relay a direct question

is relay's bounded arena in .bss (zero-init) or in a data segment, and how big per component? … I'd rather have the answer than have meld build a differential oracle against my guess

Answer: 8 KiB per component, in .bss.

Measuring it found a second, worse gap

falcon-mixer, published 1.133.0 vs the same component rebuilt with the flag:

published 1.133.0 with --emit-relocs
data segments 1 (.rodata only) 2
.rodata 76 B, end 1048652 same
.bss ABSENT (implicit zero-init) base 1048656, len 8225, end 1056881
linking section absent present, 938 B
__heap_base / __data_end absent present

The published components exposed their static end by neither route. A consumer packing by data-segment-end reserves 76 bytes for a component whose static memory ends 8,229 bytes later — silent collision, no error, no trap.

That is a worse failure mode than the relocation rejection, because the relocation path at least refuses loudly.

Two corollaries that contradict a reasonable assumption

  1. wasm-tools component new does not unconditionally strip the linking section. meld concluded it does — but inferred that from rate.wasm 1.133.0, built without --emit-relocs, so there was nothing to retain. When the section exists, it survives. Their intended no-export fallback (read __heap_base from the linking symbol table) is available.
  2. --emit-relocs also materialises .bss as an explicit zero-filled segment, so the static end is readable two independent ways that should agree.

Consequence: what was relayed as two separate supplier-side build changes — --emit-relocs for rebasing, plus retain linking/__heap_base for the extent — appears to be one flag, already merged in #352.

Confirmed on a second component

falcon-rate: 3 linking+reloc sections, __heap_base and __data_end present, memory.grow 0, wasi:* 0. It also carries a .data segment where mixer does not, so the three-segment case is covered — this is the build path, not one crate.

Criteria extended

OCI-P05 (a) now requires more than relocations: the component must also expose its true static end, by both routes, and they must agree. Relocations give the rebasing; the extent is what meld packs against.

Still implemented, not verified

Readable extent is not acceptance. meld has not fused it. v1.133 is the precedent — removing one blocker revealed a second, entirely different one, and a third remains possible.

Answered on pulseengine/meld#370 and pulseengine/jess#167.

Evidence: pinned rivet v0.19.0 validate PASS exit 0 (not local 0.28 — they disagree, 109 vs 354 warnings); gate (has-tag "oci") 7 steps PASS, 0 FAIL.

🤖 Generated with Claude Code

…locs missing

meld asked relay a direct question (meld#370): is the bounded arena in `.bss`
or a data segment, and how big? They were gating a design decision on it and
said plainly they would rather have the answer than build a differential oracle
against a guess.

Answer: 8 KiB per component, in `.bss`.

Measuring it turned up a second, larger finding than the relocation gap.
falcon-mixer, published 1.133.0 vs the same component rebuilt with the flag:

                      published 1.133.0      with --emit-relocs
  data segments       1 (.rodata only)       2
  .rodata             76 B, end 1048652      same
  .bss                ABSENT (implicit)      base 1048656, len 8225, end 1056881
  linking section     absent                 present, 938 B
  __heap_base         absent                 present
  __data_end          absent                 present

So the published components exposed their static end by NEITHER route. A
consumer packing by data-segment-end reserves 76 bytes for a component whose
static memory ends 8,229 bytes later — a silent collision, no error, no trap.
That is a WORSE failure than the relocation rejection, because the relocation
path at least refuses loudly.

TWO COROLLARIES that contradict a reasonable assumption, and both matter to the
consumer's design:

1. `wasm-tools component new` does NOT unconditionally strip the linking
   section. meld concluded it does, but inferred that from rate.wasm 1.133.0 —
   built WITHOUT --emit-relocs, so there was no linking section to retain. When
   it exists, it survives. Their intended no-export fallback (read __heap_base
   from the linking symbol table) is available.
2. `--emit-relocs` also materialises `.bss` as an explicit zero-filled segment,
   so the static end becomes readable TWO independent ways that should agree.

Consequence: what jess relayed as TWO separate supplier-side build changes
(--emit-relocs for rebasing, plus retain linking/__heap_base for the extent)
appears to be ONE flag — the one already in this PR.

Confirmed on a second component so it is the build path, not one crate:
falcon-rate gives 3 linking+reloc sections, __heap_base and __data_end present,
memory.grow 0, wasi 0 — and it carries a `.data` segment where mixer does not,
so the three-segment case is covered.

Criteria (a) extended accordingly: relocations alone are not enough; the
component must also expose its true static end, and both readings must agree.

Still `implemented`, not `verified`. Readable extent is not acceptance — meld
has not fused it. Answered on meld#370 and jess#167.

  pinned rivet v0.19.0 validate: PASS, exit 0
  gate (has-tag "oci"): 7 steps PASS, 0 FAIL

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvusAXYbHLyv3uTzfBcMbG
@avrabe
avrabe enabled auto-merge (squash) August 13, 2026 20:10
@avrabe
avrabe merged commit 7a9a711 into main Aug 13, 2026
11 checks passed
@avrabe
avrabe deleted the verify/oci-p05-extent-evidence branch August 13, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant