diff --git a/liblisa/src/semantics/default/smtgen.rs b/liblisa/src/semantics/default/smtgen.rs index 46c0db4..41ed848 100644 --- a/liblisa/src/semantics/default/smtgen.rs +++ b/liblisa/src/semantics/default/smtgen.rs @@ -137,9 +137,17 @@ impl<'ctx, A: Arch, S: SmtSolver<'ctx>> StorageLocations<'ctx, A, S> { /// Retrieves the mapping for the provided location `key`. /// If the location has no mapping, a new SMT bitvector constant is created. + /// If the register is a zero register, a bitvector with value 0 is returned. /// /// Masks the result by the mask of the location. pub fn get(&mut self, context: &mut S, key: FilledLocation, sizes: &Sizes) -> S::BV { + match key { + FilledLocation::Concrete(Location::Reg(reg)) if reg.is_zero() => { + return context.bv_from_u64(0, reg.byte_size() as u32 * 8) + } + _ => (), + } + let mask = match key { FilledLocation::Concrete(Location::Reg(reg)) => reg.mask(), _ => None, @@ -158,6 +166,7 @@ impl<'ctx, A: Arch, S: SmtSolver<'ctx>> StorageLocations<'ctx, A, S> { /// Retrieves the mapping for the provided location `key`. /// If the location has no mapping, a new SMT bitvector constant is created. + /// If the register is a zero register, a bitvector with value 0 is returned. /// /// Crops the result to the provided `input_size`. pub fn get_sized( @@ -175,12 +184,21 @@ impl<'ctx, A: Arch, S: SmtSolver<'ctx>> StorageLocations<'ctx, A, S> { /// Retrieves the mapping for the provided location `key`. /// If the location has no mapping, a new SMT bitvector constant is created. + /// If the register is a zero register, a bitvector with value 0 is returned. /// /// Does not mask or crop the result in any way. - pub fn get_raw(&mut self, context: &mut S, key: FilledLocation, sizes: &Sizes) -> &S::BV { + pub fn get_raw(&mut self, context: &mut S, key: FilledLocation, sizes: &Sizes) -> S::BV { + match key { + FilledLocation::Concrete(Location::Reg(reg)) if reg.is_zero() => { + return context.bv_from_u64(0, reg.byte_size() as u32 * 8) + } + _ => (), + } + self.map .entry(key) .or_insert_with_key(|key: &FilledLocation| context.new_bv_const(Self::name(key), key.bit_size(sizes))) + .clone() } /// Returns the bitvector constant representing the instruction bitstring. @@ -841,4 +859,4 @@ impl<'ctx, A: Arch, S: SmtSolver<'ctx>> ConcreteZ3Model<'ctx, A, S> { pub fn intermediate_values_needed(&self) -> &[usize] { &self.intermediate_values_needed } -} +} \ No newline at end of file diff --git a/liblisa/src/smt/z3/tests/mod.rs b/liblisa/src/smt/z3/tests/mod.rs index 470d7ba..69ac793 100644 --- a/liblisa/src/smt/z3/tests/mod.rs +++ b/liblisa/src/smt/z3/tests/mod.rs @@ -10,8 +10,12 @@ mod equivalence; use std::time::Duration; +use crate::arch::x64::{GpReg, X64Arch, X64Reg}; +use crate::encoding::dataflows::Size; +use crate::semantics::default::smtgen::{FilledLocation, Sizes, StorageLocations}; use crate::smt::z3::Z3Solver; use crate::smt::{SatResult, SmtBV, SmtBVArray, SmtSolver}; +use crate::state::Location; #[test] pub fn array_store_select_equals() { @@ -24,3 +28,27 @@ pub fn array_store_select_equals() { assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat)); }); } + +#[test] +pub fn zero_register_is_zero() { + // Verify that the value of a zero register returned by StorageLocations is, in fact, always zero. + Z3Solver::with_thread_local(Duration::from_secs(900), |mut context| { + let mut s = StorageLocations::::new(&mut context); + let key = FilledLocation::Concrete(Location::Reg(X64Reg::GpReg(GpReg::Riz))); + + // StorageLocations::get + let riz = s.get(&mut context, key, &Sizes::default()); + let eq = !riz._eq(context.bv_from_u64(0, 64)); + assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat)); + + // StorageLocations::get_sized + let riz = s.get_sized(&mut context, key, &Sizes::default(), Size::qword(), false); + let eq = !riz._eq(context.bv_from_u64(0, 64)); + assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat)); + + // StorageLocations::get_raw + let riz = s.get_raw(&mut context, key, &Sizes::default()); + let eq = !riz._eq(context.bv_from_u64(0, 64)); + assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat)); + }); +}