Skip to content

Commit

Permalink
fix(sym-exec): handle JUMP loops as well
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon-Becker committed Dec 27, 2023
1 parent b9d777f commit 7b70f72
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
83 changes: 83 additions & 0 deletions common/src/ether/evm/ext/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,89 @@ impl VM {
}
}

// if we encounter a JUMP
if state.last_instruction.opcode == 0x56 {
// build hashable jump frame
let jump_frame = JumpFrame::new(
state.last_instruction.instruction,
state.last_instruction.inputs[0],
vm.stack.size(),
true,
);

// perform heuristic checks on historical stacks
match handled_jumps.get_mut(&jump_frame) {
Some(historical_stacks) => {
// for every stack that we have encountered for this jump, perform some
// heuristic checks to determine if this might be a loop
if historical_stacks.iter().any(|hist_stack| {
// check if any historical stack is the same as the current stack
if hist_stack == &vm.stack {
debug_max!(
"jump matches loop-detection heuristic: 'jump_path_already_handled'"
);
return true
}

// calculate the difference of the current stack and the historical stack
let stack_diff = stack_diff(&vm.stack, hist_stack);
if stack_diff.is_empty() {
// the stack_diff is empty (the stacks are the same), so we've
// already handled this path
debug_max!(
"jump matches loop-detection heuristic: 'stack_diff_is_empty'"
);
return true
}

debug_max!("stack diff: [{}]", stack_diff.iter().map(|frame| format!("{}", frame.value)).collect::<Vec<String>>().join(", "));

false
}) {
debug_max!("jump terminated.");
debug_max!(
"adding historical stack {} to jump frame {:?}",
&format!("{:#016x?}", vm.stack.hash()),
jump_frame
);

// this key exists, but the stack is different, so the jump is new
historical_stacks.push(vm.stack.clone());
return vm_trace
}

if jump_condition_historical_diffs_approximately_equal(
&vm.stack,
historical_stacks,
) {
debug_max!("jump terminated.");
debug_max!(
"adding historical stack {} to jump frame {:?}",
&format!("{:#016x?}", vm.stack.hash()),
jump_frame
);

// this key exists, but the stack is different, so the jump is new
historical_stacks.push(vm.stack.clone());
return vm_trace;
} else {
debug_max!(
"adding historical stack {} to jump frame {:?}",
&format!("{:#016x?}", vm.stack.hash()),
jump_frame
);
// this key exists, but the stack is different, so the jump is new
historical_stacks.push(vm.stack.clone());
}
}
None => {
// this key doesnt exist, so the jump is new
debug_max!("added new jump frame: {:?}", jump_frame);
handled_jumps.insert(jump_frame, vec![vm.stack.clone()]);
}
}
}

// when the vm exits, this path is complete
if vm.exitcode != 255 || !vm.returndata.is_empty() {
break;
Expand Down
4 changes: 4 additions & 0 deletions core/tests/test_decompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ mod integration_tests {
"0xd1d2Eb1B1e90B638588728b4130137D262C87cae",
"0x95e05e2Abbd26943874ac000D87C3D9e115B543c",
"0x00000000A991C429eE2Ec6df19d40fe0c80088B8",
"0x737673b5e0a3c68adf4c1a87bca5623cfc537ec3",
"0x940259178FbF021e625510919BC2FF0B944E5613",
"0xff612db0583be8d5498731e4e32bc12e08fa6292",
"0xd5FEa30Ed719693Ec8848Dc7501b582F5de6a5BB",
];

// define flag checks
Expand Down

0 comments on commit 7b70f72

Please sign in to comment.