Skip to content

Commit

Permalink
Bugfix: arithmetic overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Nov 17, 2024
1 parent bb60476 commit 9677f1c
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 11 deletions.
9 changes: 9 additions & 0 deletions tests/should_perform_calculations_with_overflow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod utils;
use utils::get_int;
use vm::vm::VM;

#[test]
fn should_perform_calculations_with_overflow() {
let last_frame_value = VM::run("samples.arithmetics.overflow.ArithmeticOverflow").unwrap();
assert_eq!(1, get_int(last_frame_value))
}
184 changes: 184 additions & 0 deletions tests/test_data/ArithmeticOverflow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package samples.arithmetics.overflow;

public class ArithmeticOverflow {
public static void main(String[] args) {
int intsResult = intsOverflow();
int longsResult = longsOverflow();

boolean result = intsResult == 511 && longsResult == 511;
}

private static int intsOverflow() {
// Add
int addOverflow = getAddOverflow(1);
int bit0 = addOverflow == -2147483648 ? 1 : 0;

// Multiply
int mulOverflow = getMulOverflow(2);
int bit1 = mulOverflow == -2 ? 1 : 0;

// Division
int divOverflow = getDivOverflow(-1); // Causes overflow
int bit2 = divOverflow == -2147483648 ? 1 : 0;

// Negation
int negOverflow = getNegOverflow(Integer.MIN_VALUE); // Integer.MIN_VALUE has no positive counterpart
int bit3 = negOverflow == -2147483648 ? 1 : 0;

// Remainder
int remOverflow = getRemOverflow(-1); // Same as division overflow
int bit4 = remOverflow == 0 ? 1 : 0;

// Shift Left
int shlOverflow = getShlOverflow(1); // Shifting may cause bits to overflow
int bit5 = shlOverflow == -2 ? 1 : 0;

// Shift Right
int shrOverflow = getShrOverflow(1); // Arithmetic shift retains sign, but no overflow
int bit6 = shrOverflow == -1073741824 ? 1 : 0;

int uShlOverflow = getUShlOverflow(1);// Logical shift retains sign, but no overflow
int bit7 = uShlOverflow == 1073741824 ? 1 : 0;

// Subtract
int subOverflow = getSubOverflow(1);
int bit8 = subOverflow == 2147483647 ? 1 : 0;

int result = 0;
result = setBit(result, 0, bit0);
result = setBit(result, 1, bit1);
result = setBit(result, 2, bit2);
result = setBit(result, 3, bit3);
result = setBit(result, 4, bit4);
result = setBit(result, 5, bit5);
result = setBit(result, 6, bit6);
result = setBit(result, 7, bit7);
result = setBit(result, 8, bit8);
return result;
}

private static int longsOverflow() {
// Add
long addOverflow = getAddOverflow(1L);
int bit0 = addOverflow == Long.MIN_VALUE ? 1 : 0;

// Multiply
long mulOverflow = getMulOverflow(2L);
int bit1 = mulOverflow == -2L ? 1 : 0;

// Division
long divOverflow = getDivOverflow(-1L); // Causes overflow
int bit2 = divOverflow == Long.MIN_VALUE ? 1 : 0;

// Negation
long negOverflow = getNegOverflow(Long.MIN_VALUE); // Long.MIN_VALUE has no positive counterpart
int bit3 = negOverflow == Long.MIN_VALUE ? 1 : 0;

// Remainder
long remOverflow = getRemOverflow(-1L); // Same as division overflow
int bit4 = remOverflow == 0L ? 1 : 0;

// Shift Left
long shlOverflow = getShlOverflow(1L); // Shifting may cause bits to overflow
int bit5 = shlOverflow == -2L ? 1 : 0;

// Shift Right
long shrOverflow = getShrOverflow(1L); // Arithmetic shift retains sign, but no overflow
int bit6 = shrOverflow == -4611686018427387904L ? 1 : 0;

long uShlOverflow = getUShlOverflow(1L); // Logical shift retains sign, but no overflow
int bit7 = uShlOverflow == 4611686018427387904L ? 1 : 0;

// Subtract
long subOverflow = getSubOverflow(1L);
int bit8 = subOverflow == Long.MAX_VALUE ? 1 : 0;

int result = 0;
result = setBit(result, 0, bit0);
result = setBit(result, 1, bit1);
result = setBit(result, 2, bit2);
result = setBit(result, 3, bit3);
result = setBit(result, 4, bit4);
result = setBit(result, 5, bit5);
result = setBit(result, 6, bit6);
result = setBit(result, 7, bit7);
result = setBit(result, 8, bit8);
return result;
}

private static int getSubOverflow(int value) {
return Integer.MIN_VALUE - value;
}

private static int getShrOverflow(int value) {
return Integer.MIN_VALUE >> value;
}

private static int getShlOverflow(int value) {
return Integer.MAX_VALUE << value;
}

private static int getUShlOverflow(int value) {
return Integer.MIN_VALUE >>> value;
}

private static int getRemOverflow(int value) {
return Integer.MIN_VALUE % value;
}

private static int getNegOverflow(int value) {
return -value;
}

private static int getDivOverflow(int value) {
return Integer.MIN_VALUE / value;
}

private static int getMulOverflow(int value) {
return Integer.MAX_VALUE * value;
}

private static int getAddOverflow(int value) {
return Integer.MAX_VALUE + value;
}

private static long getSubOverflow(long value) {
return Long.MIN_VALUE - value;
}

private static long getShrOverflow(long value) {
return Long.MIN_VALUE >> value;
}

private static long getShlOverflow(long value) {
return Long.MAX_VALUE << value;
}

private static long getUShlOverflow(long value) {
return Long.MIN_VALUE >>> value;
}

private static long getRemOverflow(long value) {
return Long.MIN_VALUE % value;
}

private static long getNegOverflow(long value) {
return -value;
}

private static long getDivOverflow(long value) {
return Long.MIN_VALUE / value;
}

private static long getMulOverflow(long value) {
return Long.MAX_VALUE * value;
}

private static long getAddOverflow(long value) {
return Long.MAX_VALUE + value;
}

private static int setBit(int num, int position, int value) {
return value == 0 ? num & ~(1 << position) : num | (1 << position);
}
}
Binary file not shown.
22 changes: 11 additions & 11 deletions vm/src/execution_engine/ops_math_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
IADD => {
let b: i32 = stack_frame.pop();
let a: i32 = stack_frame.pop();
let result = a + b;
let result = a.wrapping_add(b);
stack_frame.push(result);

stack_frame.incr_pc();
Expand Down Expand Up @@ -48,7 +48,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
ISUB => {
let b: i32 = stack_frame.pop();
let a: i32 = stack_frame.pop();
let result = a - b;
let result = a.wrapping_sub(b);
stack_frame.push(result);

stack_frame.incr_pc();
Expand All @@ -58,7 +58,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
let b: i64 = stack_frame.pop();
let a: i64 = stack_frame.pop();

let result = a - b;
let result = a.wrapping_sub(b);

stack_frame.push(result);

Expand Down Expand Up @@ -128,7 +128,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
IDIV => {
let b: i32 = stack_frame.pop();
let a: i32 = stack_frame.pop();
let result = a / b; //todo add check for ArithmeticException here
let result = a.wrapping_div(b); //todo add check for ArithmeticException here
stack_frame.push(result);

stack_frame.incr_pc();
Expand All @@ -138,7 +138,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
let b: i64 = stack_frame.pop();
let a: i64 = stack_frame.pop();

let result = a / b; //todo add check for ArithmeticException here
let result = a.wrapping_div(b); //todo add check for ArithmeticException here

stack_frame.push(result);

Expand Down Expand Up @@ -168,7 +168,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
IREM => {
let b: i32 = stack_frame.pop();
let a: i32 = stack_frame.pop();
let result = a % b;
let result = a.wrapping_rem(b);
stack_frame.push(result);

stack_frame.incr_pc();
Expand All @@ -178,7 +178,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
let b: i64 = stack_frame.pop();
let a: i64 = stack_frame.pop();

let result = a % b;
let result = a.wrapping_rem(b);

stack_frame.push(result);

Expand All @@ -198,15 +198,15 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
}
INEG => {
let value: i32 = stack_frame.pop();
let result = -value;
let result = value.wrapping_neg();
stack_frame.push(result);

stack_frame.incr_pc();
trace!("INEG -> {result}");
}
LNEG => {
let value: i64 = stack_frame.pop();
let result = -value;
let result = value.wrapping_neg();
stack_frame.push(result);

stack_frame.incr_pc();
Expand Down Expand Up @@ -266,7 +266,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
stack_frame.push(result);

stack_frame.incr_pc();
trace!("IUSHR -> {a} >> {b} = {result}");
trace!("IUSHR -> {a} >>> {b} = {result}");
}
LUSHR => {
let b: i32 = stack_frame.pop();
Expand All @@ -277,7 +277,7 @@ pub(crate) fn process(code: u8, stack_frames: &mut Vec<StackFrame>) -> crate::er
stack_frame.push(result);

stack_frame.incr_pc();
trace!("LUSHR -> {a} >> {b} = {result}");
trace!("LUSHR -> {a} >>> {b} = {result}");
}
IAND => {
let b: i32 = stack_frame.pop();
Expand Down

0 comments on commit 9677f1c

Please sign in to comment.