fix(evm): use deque for execution cache to prevent pointer invalidation#362
Open
starwarfan wants to merge 1 commit intoDTVMStack:mainfrom
Open
fix(evm): use deque for execution cache to prevent pointer invalidation#362starwarfan wants to merge 1 commit intoDTVMStack:mainfrom
starwarfan wants to merge 1 commit intoDTVMStack:mainfrom
Conversation
Runtime functions like evmGetExtCodeHash and evmGetKeccak256 return pointers to bytes32 values stored in ExecutionCache vectors. The JIT defers loading these bytes until the value is consumed by a later opcode. When a second push_back triggers vector reallocation, all previously returned pointers become dangling, causing the JIT to read garbage data and spuriously trip the out-of-gas or overflow traps. Replace std::vector with std::deque for ExtcodeHashes and Keccak256Results, since deque::push_back preserves references to existing elements. Made-with: Cursor
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a multipass JIT use-after-free by ensuring pointers returned from runtime helpers (e.g., EXTCODEHASH/KECCAK256) remain valid even after additional cached results are appended during execution.
Changes:
- Switch
ExecutionCache::ExtcodeHashesfromstd::vectortostd::dequeto avoid pointer invalidation on reallocation. - Switch
ExecutionCache::Keccak256Resultsfromstd::vectortostd::dequefor the same reason. - Add the required
<deque>include.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runtime functions like
evmGetExtCodeHashandevmGetKeccak256return pointers toevmc::bytes32values stored inExecutionCachevectors. The JIT defers loading these bytes until the value is consumed by a later opcode (e.g. when KECCAK256 reads offset/size produced by prior EXTCODEHASH calls). When a secondpush_backtriggersstd::vectorreallocation, all previously returned pointers become dangling, causing the JIT to read garbage data and spuriously trip the out-of-gas or overflow traps.Fixes 17 reproducing fuzz crashes in multipass JIT mode (status mismatches and gas mismatches involving EXTCODEHASH/KECCAK256).
1. Does this PR affect any open issues?(Y/N) and add issue references (e.g. "fix #123", "re #123".):
2. What is the scope of this PR (e.g. component or file name):
src/runtime/evm_instance.h
3. Provide a description of the PR(e.g. more details, effects, motivations or doc link):
Root cause:
ExecutionCache::ExtcodeHashesandExecutionCache::Keccak256Resultsarestd::vector<evmc::bytes32>. Runtime functions such asevmGetExtCodeHashdopush_backand return a pointer toback().bytes. The multipass JIT stores this pointer in a MIR variable and only dereferences it later (whenconvertBytes32ToU256Operandgenerates loads). If a subsequent runtime call pushes another element, the vector may reallocate, invalidating the earlier pointer. The JIT then loads from freed memory, producing garbage uint256 values whose upper limbs are non-zero, which triggers thenormalizeOperandU64overflow trap (mapped toGasLimitExceeded).Fix: Replace
std::vectorwithstd::dequefor both fields.std::deque::push_backguarantees that references to existing elements remain valid, eliminating the use-after-free.4. Are there any breaking changes?(Y/N) and describe the breaking changes(e.g. more details, motivations or doc link):
5. Are there test cases for these changes?(Y/N) select and add more details, references or doc links:
Verified by re-running all 24 remaining fuzz crash files (post-SLT/SGT fix) with
evmone-fuzzerin multipass mode. 17 previously failing crashes now pass. The remaining 7 crashes are all on Frontier (rev=0) and are unrelated to this fix.6. Release note
Made with Cursor