Skip to content

fix(codegen): prevent index out of bounds in dead_storage reaching_definitions#1888

Open
ArshLabs wants to merge 1 commit intohyperledger-solang:mainfrom
ArshLabs:fix/issue-1876-dead-storage-empty-vec
Open

fix(codegen): prevent index out of bounds in dead_storage reaching_definitions#1888
ArshLabs wants to merge 1 commit intohyperledger-solang:mainfrom
ArshLabs:fix/issue-1876-dead-storage-empty-vec

Conversation

@ArshLabs
Copy link
Copy Markdown

@ArshLabs ArshLabs commented Apr 24, 2026

What panics and where

solang compile --target polkadot panics with:

thread 'main' panicked at src/codegen/dead_storage.rs:376:16:
index out of bounds: the len is 0 but the index is 0

The panic is in apply_transfers() at the line:

*vars = res[0].clone();

res is built by iterating over transfers in the first pass (lines 343–371). When a basic block has zero instructions — which happens with a Yul for loop whose body contains only continuetransfers is empty, res is never pushed to, and indexing res[0] panics.

Root cause: two cooperating bugs

Bug 1 — dead_storage.rs: apply_transfers() does not guard against an empty transfers/res before indexing res[0]. The fix is a four-line early-return that records the current reaching-definition set for the block and returns without touching *vars, which is the correct semantic: an empty block has no transfers, so the outgoing state equals the incoming state.

Bug 2 — sema/yul/for_loop.rs: resolve_for_loop() computed post-block reachability purely from whether the body block fell through (resolved_exec_block.1). A body that ends with a reachable continue always reaches the post block but never falls through, so post-block reachability was incorrectly set to false. Codegen then skipped the post block's instructions entirely, producing an empty basic block with zero instructions — the direct trigger for Bug 1. The fix adds a helper (block_ends_with_reachable_continue) that walks the body's last reachable statement and ORs its result into the post-block reachability flag.

Changes

  • src/codegen/dead_storage.rs — guard apply_transfers() against empty transfers/res.
  • src/sema/yul/for_loop.rs — fix post-block reachability when body ends with a reachable continue; add block_ends_with_reachable_continue and statement_ends_with_reachable_continue helpers.
  • tests/polkadot_tests/yul.rs — regression test continue_only_for_body that reproduces the MRE from the issue.

Minimum reproducer

contract C {
    function f() public pure {
        assembly {
            for { let i := 0 } lt(i, 1) { i := add(i, 1) } { continue }
        }
    }
}
solang compile --target polkadot mre.sol

Before this fix: compiler panics. After this fix: compiles cleanly.

Fixes #1876

…finitions

Signed-off-by: Arshdeep Singh <arshdeep.ssingh777@gmail.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.

Compiler panic in codegen: index out of bounds: the len is 0 but the index is 0 in dead_storage::reaching_definitions

1 participant