Skip to content

Commit

Permalink
perf: switch partial reads to use bitwise AND
Browse files Browse the repository at this point in the history
This switches partial `read` syscalls (i.e. those that don't read
multiples of 8 bytes) to use bitwise AND operators instead of MUL and
DIV when combining values bytewise. The goal is to produce a simpler
formula for the solver. Note that incomplete solvers in particular have
a hard time solving "t = x * (2^N) / (2^N)" for example.
  • Loading branch information
mstarzinger committed Jul 22, 2021
1 parent e1c9a4e commit ec74690
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 40 deletions.
19 changes: 19 additions & 0 deletions examples/test-sltu-3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
uint64_t main() {
uint64_t a;
uint64_t* x;

x = malloc(8);

*x = 0;

read(0, x, 4);

a = *x - 48;

if (a < 9)
return 0;
if (a == 9)
return 1;

return 0;
}
31 changes: 9 additions & 22 deletions src/engine/symbolic_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,47 +680,34 @@ where
new_idx: SymbolicValue,
) -> SymbolicValue {
let bits_in_a_byte = 8;
let low_shift_factor = 2_u64.pow(n_lower_bytes * bits_in_a_byte);
let high_shift_factor =
2_u64.pow((size_of::<u64>() as u32 - n_lower_bytes) * bits_in_a_byte);
let high_mask = (1_u64 << (n_lower_bytes * bits_in_a_byte)) - 1;
let low_mask = !high_mask;

assert!(
low_shift_factor != 0 && high_shift_factor != 0,
"no bytes to shift"
);
assert!(low_mask ^ high_mask == u64::max_value(), "must complement");
assert!(high_mask != u64::max_value(), "nothing to mask");

let old_idx = match old {
Value::Concrete(c) => {
let old_c = c / low_shift_factor * low_shift_factor;
let old_c = c & low_mask;

self.symbolic_state.create_const(old_c)
}
Value::Symbolic(old_idx) => {
let low_shift_factor_idx = self.symbolic_state.create_const(low_shift_factor);

let old_idx = self.symbolic_state.create_operator(
BVOperator::Divu,
old_idx,
low_shift_factor_idx,
);
let low_mask_idx = self.symbolic_state.create_const(low_mask);

self.symbolic_state
.create_operator(BVOperator::Mul, old_idx, low_shift_factor_idx)
.create_operator(BVOperator::BitwiseAnd, old_idx, low_mask_idx)
}
Value::Uninitialized => {
unreachable!("function should not be called for uninitialized values")
}
};

let high_shift_factor_idx = self.symbolic_state.create_const(high_shift_factor);

let new_idx =
self.symbolic_state
.create_operator(BVOperator::Mul, new_idx, high_shift_factor_idx);
let high_mask_idx = self.symbolic_state.create_const(high_mask);

let new_idx =
self.symbolic_state
.create_operator(BVOperator::Divu, new_idx, high_shift_factor_idx);
.create_operator(BVOperator::BitwiseAnd, new_idx, high_mask_idx);

self.symbolic_state
.create_operator(BVOperator::Add, old_idx, new_idx)
Expand Down
28 changes: 10 additions & 18 deletions tests/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,20 @@ use monster::{
symbolically_execute_with, MonsterError, SymbolicExecutionBug, SymbolicExecutionOptions,
};
use rayon::prelude::*;
use std::{
path::{Path, PathBuf},
time::Duration,
};
use std::path::{Path, PathBuf};
use utils::{compile_riscu, init, with_temp_dir};

const TEST_FILES: [&str; 22] = [
const TEST_FILES: [&str; 23] = [
"arithmetic.c",
"echo-line.c",
"if-else.c", // needs timeout
"if-else.c",
"invalid-memory-access-2-35.c",
"division-by-zero-3-35.c",
"simple-assignment-1-35.c",
"test-remu.c",
"test-sltu.c",
"test-sltu-2.c",
"test-sltu-3.c",
"memory-access-1-35.c",
"memory-invalid-read.c",
"memory-invalid-write.c",
Expand All @@ -43,8 +41,7 @@ const TEST_FILES: [&str; 22] = [

#[test]
fn execute_riscu_with_monster_solver() {
// need a big timeout because of the slow Github runners
let solver = MonsterSolver::new(Duration::new(5, 0));
let solver = MonsterSolver::default();
execute_riscu_examples(&TEST_FILES, &solver);
}

Expand Down Expand Up @@ -116,8 +113,7 @@ fn execute_default_with<P: AsRef<Path>>(
object: P,
options: &SymbolicExecutionOptions,
) -> Result<(Option<SymbolicExecutionBug>, Profiler), MonsterError> {
// need a big timeout because of the slow Github runners
let solver = MonsterSolver::new(Duration::new(5, 0));
let solver = MonsterSolver::default();

execute_default_with_solver(object, options, &solver)
}
Expand Down Expand Up @@ -145,14 +141,7 @@ fn execute_riscu_examples<S: Solver>(names: &'static [&str], solver: &S) {
fn execute_riscu<S: Solver>(source: PathBuf, object: PathBuf, solver: &S) {
let file_name = source.file_name().unwrap().to_str().unwrap();

let options = SymbolicExecutionOptions {
max_exection_depth: match file_name {
"two-level-nested-loop-1-35.c" => 230,
"recursive-fibonacci-1-10.c" => 300,
_ => 1000,
},
..Default::default()
};
let options = SymbolicExecutionOptions::default();

let result = execute_default_with_solver(object, &options, solver);

Expand Down Expand Up @@ -204,6 +193,9 @@ fn execute_riscu<S: Solver>(source: PathBuf, object: PathBuf, solver: &S) {
) | (
"test-sltu-2.c",
SymbolicExecutionBug::ExitCodeGreaterZero { .. }
) | (
"test-sltu-3.c",
SymbolicExecutionBug::ExitCodeGreaterZero { .. }
) | (
"memory-access-1-35.c",
SymbolicExecutionBug::AccessToUnitializedMemory { .. }
Expand Down

0 comments on commit ec74690

Please sign in to comment.