Skip to content

Commit 2bf96b3

Browse files
fix(levm): handle sdiv with zero dividend and negative divisor (#1241)
**Motivation** Fixes a bug found by [FuzzingLabs](https://github.com/FuzzingLabs) in `sdiv` opcode implementation. **Description** The error happened when executing sdiv with a zero dividend and a negative divisor, and returned something that is not zero (it's negated). Closes #1199
1 parent 2e42cdf commit 2bf96b3

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

crates/vm/levm/src/opcode_handlers/arithmetic.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl VM {
7575

7676
let dividend = current_call_frame.stack.pop()?;
7777
let divisor = current_call_frame.stack.pop()?;
78-
if divisor.is_zero() {
78+
if divisor.is_zero() || dividend.is_zero() {
7979
current_call_frame.stack.push(U256::zero())?;
8080
return Ok(OpcodeSuccess::Continue);
8181
}
@@ -92,15 +92,16 @@ impl VM {
9292
} else {
9393
divisor
9494
};
95-
let Some(quotient) = dividend.checked_div(divisor) else {
96-
current_call_frame.stack.push(U256::zero())?;
97-
return Ok(OpcodeSuccess::Continue);
98-
};
99-
let quotient_is_negative = dividend_is_negative ^ divisor_is_negative;
100-
let quotient = if quotient_is_negative {
101-
negate(quotient)
102-
} else {
103-
quotient
95+
let quotient = match dividend.checked_div(divisor) {
96+
Some(quot) => {
97+
let quotient_is_negative = dividend_is_negative ^ divisor_is_negative;
98+
if quotient_is_negative {
99+
negate(quot)
100+
} else {
101+
quot
102+
}
103+
}
104+
None => U256::zero(),
104105
};
105106

106107
current_call_frame.stack.push(quotient)?;

crates/vm/levm/tests/edge_case_tests.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,16 @@ fn test_is_negative() {
101101
let mut current_call_frame = vm.call_frames.pop().unwrap();
102102
vm.execute(&mut current_call_frame);
103103
}
104+
105+
#[test]
106+
fn test_sdiv_zero_dividend_and_negative_divisor() {
107+
let mut vm = new_vm_with_bytecode(Bytes::copy_from_slice(&[
108+
0x7F, 0xC5, 0xD2, 0x46, 0x01, 0x86, 0xF7, 0x23, 0x3C, 0x92, 0x7E, 0x7D, 0xB2, 0xDC, 0xC7,
109+
0x03, 0xC0, 0xE5, 0x00, 0xB6, 0x53, 0xCA, 0x82, 0x27, 0x3B, 0x7B, 0xFA, 0xD8, 0x04, 0x5D,
110+
0x85, 0xA4, 0x70, 0x5F, 0x05,
111+
]))
112+
.unwrap();
113+
let mut current_call_frame = vm.call_frames.pop().unwrap();
114+
vm.execute(&mut current_call_frame);
115+
assert_eq!(current_call_frame.stack.pop().unwrap(), U256::zero());
116+
}

0 commit comments

Comments
 (0)