Skip to content

fix: properly free BeamState on error paths to prevent segfaults (closes #675)#676

Merged
anshalshukla merged 4 commits intomainfrom
fix/memory-leaks-675
Mar 16, 2026
Merged

fix: properly free BeamState on error paths to prevent segfaults (closes #675)#676
anshalshukla merged 4 commits intomainfrom
fix/memory-leaks-675

Conversation

@zclawz
Copy link
Copy Markdown
Contributor

@zclawz zclawz commented Mar 16, 2026

Problem

Fixes #675 — zeam segfaults on InvalidPostState when processing a cached block.

Root cause: In onBlock's computedstate: labeled block, cpost_state is heap-allocated with allocator.create and then deep-cloned via sszClone (which allocates interior ArrayList fields like historical_block_hashes, justified_slots, etc.). If verifySignatures or apply_transition subsequently fails, there were no errdefer cleanup paths — the partially-mutated state leaked, causing UB and the observed segfault.

Specifically: apply_transition calls process_slots which appends to historical_block_hashes before the post-state root check. When InvalidPostState is returned, those appended bytes are never freed → dangling allocations → segfault.

Fix — three errdefer additions in chain.zig

1. onBlock — inside computedstate: block

LIFO errdefer pair: destroy registered first (covers sszClone failure), then deinit registered after clone succeeds (covers verifySignatures / apply_transition failure). When both fire, deinit runs first freeing interior fields, then destroy frees the outer struct.

2. onBlock — function level (post-state ownership)

If computedstate: succeeds but a later step fails (forkChoice.onBlock, updateHead, InvalidSignatureGroups), post_state was previously leaked. Added errdefer guarded by post_state_owned flag.

3. BeamChain.initcloned_anchor_state

Same create+sszClone pattern without cleanup if states.put fails.

zclawz added 3 commits March 13, 2026 11:56
 #675)

Three memory-safety fixes in chain.zig:

1. onBlock — computedstate block: add errdefer for cpost_state
   - After allocator.create(): errdefer destroy (covers sszClone failure)
   - After sszClone(): errdefer deinit (covers verifySignatures / apply_transition
     failures, e.g. InvalidPostState). LIFO ordering ensures deinit runs before
     destroy, so interior ArrayList fields are freed cleanly.
   - Previously: a partially-mutated cloned state (historical_block_hashes already
     appended by process_slots) was silently leaked, causing UB / segfault.

2. onBlock — function level: add errdefer for post_state when we own it
   - If computedstate succeeds but a later step (forkChoice.onBlock, updateHead,
     InvalidSignatureGroups) returns an error, post_state was previously leaked.

3. BeamChain init — cloned_anchor_state: add errdefer before states.put
   - Same create+sszClone pattern without cleanup on states.put failure.
@anshalshukla anshalshukla merged commit fe8c8eb into main Mar 16, 2026
8 checks passed
@anshalshukla anshalshukla deleted the fix/memory-leaks-675 branch March 16, 2026 17:44
GrapeBaBa pushed a commit that referenced this pull request Apr 2, 2026
 #675) (#676)

* fix: replace {any} with {f} for types with format methods, fix GossipTopic format signature (closes #594)

* fix: replace all {any} with {f} for types with custom format methods (closes #594)

* fix: properly free BeamState on error paths to prevent segfaults (closes #675)

Three memory-safety fixes in chain.zig:

1. onBlock — computedstate block: add errdefer for cpost_state
   - After allocator.create(): errdefer destroy (covers sszClone failure)
   - After sszClone(): errdefer deinit (covers verifySignatures / apply_transition
     failures, e.g. InvalidPostState). LIFO ordering ensures deinit runs before
     destroy, so interior ArrayList fields are freed cleanly.
   - Previously: a partially-mutated cloned state (historical_block_hashes already
     appended by process_slots) was silently leaked, causing UB / segfault.

2. onBlock — function level: add errdefer for post_state when we own it
   - If computedstate succeeds but a later step (forkChoice.onBlock, updateHead,
     InvalidSignatureGroups) returns an error, post_state was previously leaked.

3. BeamChain init — cloned_anchor_state: add errdefer before states.put
   - Same create+sszClone pattern without cleanup on states.put failure.

---------

Co-authored-by: zclawz <zclawz@blockblaz.io>
Co-authored-by: Anshal Shukla <53994948+anshalshukla@users.noreply.github.com>
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.

bug: zeam segfault on InvalidPostState

3 participants