Unverified Commit d3dde7d7 by Enkelmann Committed by GitHub

move the new_top() function to the HasByteSize trait. (#124)

parent 809b7ca8
...@@ -44,14 +44,14 @@ impl HasByteSize for BitvectorDomain { ...@@ -44,14 +44,14 @@ impl HasByteSize for BitvectorDomain {
Value(bitvec) => bitvec.width().into(), Value(bitvec) => bitvec.width().into(),
} }
} }
}
impl RegisterDomain for BitvectorDomain {
/// Get a *Top* element with the given bitsize. /// Get a *Top* element with the given bitsize.
fn new_top(bytesize: ByteSize) -> BitvectorDomain { fn new_top(bytesize: ByteSize) -> BitvectorDomain {
BitvectorDomain::Top(bytesize) BitvectorDomain::Top(bytesize)
} }
}
impl RegisterDomain for BitvectorDomain {
/// Evaluate the given binary operation. /// Evaluate the given binary operation.
/// ///
/// For non-shift operations, this function will panic if the operands have different bitsizes. /// For non-shift operations, this function will panic if the operands have different bitsizes.
......
...@@ -72,6 +72,11 @@ impl<T: RegisterDomain> HasByteSize for DataDomain<T> { ...@@ -72,6 +72,11 @@ impl<T: RegisterDomain> HasByteSize for DataDomain<T> {
Value(bitvec) => bitvec.bytesize(), Value(bitvec) => bitvec.bytesize(),
} }
} }
// Return a new *Top* element with the given bytesize
fn new_top(bytesize: ByteSize) -> Self {
Self::Top(bytesize)
}
} }
impl<T: RegisterDomain> HasTop for DataDomain<T> { impl<T: RegisterDomain> HasTop for DataDomain<T> {
...@@ -82,11 +87,6 @@ impl<T: RegisterDomain> HasTop for DataDomain<T> { ...@@ -82,11 +87,6 @@ impl<T: RegisterDomain> HasTop for DataDomain<T> {
} }
impl<T: RegisterDomain> RegisterDomain for DataDomain<T> { impl<T: RegisterDomain> RegisterDomain for DataDomain<T> {
// Return a new *Top* element with the given bytesize
fn new_top(bytesize: ByteSize) -> Self {
Self::Top(bytesize)
}
/// Compute the (abstract) result of a binary operation /// Compute the (abstract) result of a binary operation
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self { fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self {
use BinOpType::*; use BinOpType::*;
......
use super::{AbstractDomain, HasByteSize, HasTop, RegisterDomain}; use super::{AbstractDomain, HasByteSize, HasTop};
use crate::bil::Bitvector; use crate::bil::Bitvector;
use crate::intermediate_representation::ByteSize; use crate::intermediate_representation::ByteSize;
use apint::{Int, Width}; use apint::{Int, Width};
...@@ -10,7 +10,8 @@ use std::sync::Arc; ...@@ -10,7 +10,8 @@ use std::sync::Arc;
/// A memory region is an abstract domain representing a continuous region of memory, e.g. the stack frame of a function. /// A memory region is an abstract domain representing a continuous region of memory, e.g. the stack frame of a function.
/// ///
/// This implementation can only save values of one `RegisterDomain` type /// This implementation can only save values of one abstract domain type,
/// which must implement the `HasByteSize` and `HasTop` domains,
/// and it can only track values with a known offset, i.e. it cannot handle arrays of any kind. /// and it can only track values with a known offset, i.e. it cannot handle arrays of any kind.
/// Offsets are internally saved as signed integers, which allows negative offsets, /// Offsets are internally saved as signed integers, which allows negative offsets,
/// e.g. for downward growing stack frames. /// e.g. for downward growing stack frames.
...@@ -21,19 +22,17 @@ use std::sync::Arc; ...@@ -21,19 +22,17 @@ use std::sync::Arc;
/// To allow cheap cloning of a `MemRegion`, the actual data is wrapped inside an `Arc`. /// To allow cheap cloning of a `MemRegion`, the actual data is wrapped inside an `Arc`.
#[derive(Serialize, Deserialize, Debug, Hash, Clone, PartialEq, Eq, Deref)] #[derive(Serialize, Deserialize, Debug, Hash, Clone, PartialEq, Eq, Deref)]
#[deref(forward)] #[deref(forward)]
pub struct MemRegion<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug>( pub struct MemRegion<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug>(
Arc<MemRegionData<T>>, Arc<MemRegionData<T>>,
); );
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> DerefMut for MemRegion<T> { impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> DerefMut for MemRegion<T> {
fn deref_mut(&mut self) -> &mut MemRegionData<T> { fn deref_mut(&mut self) -> &mut MemRegionData<T> {
Arc::make_mut(&mut self.0) Arc::make_mut(&mut self.0)
} }
} }
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> AbstractDomain impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> AbstractDomain for MemRegion<T> {
for MemRegion<T>
{
/// Short-circuting the `MemRegionData::merge` function if `self==other`, /// Short-circuting the `MemRegionData::merge` function if `self==other`,
/// to prevent unneccessary cloning. /// to prevent unneccessary cloning.
fn merge(&self, other: &Self) -> Self { fn merge(&self, other: &Self) -> Self {
...@@ -50,14 +49,14 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> Abstrac ...@@ -50,14 +49,14 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> Abstrac
} }
} }
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> HasTop for MemRegion<T> { impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> HasTop for MemRegion<T> {
/// Return a new, empty memory region with the same address bytesize as `self`, representing the *Top* element of the abstract domain. /// Return a new, empty memory region with the same address bytesize as `self`, representing the *Top* element of the abstract domain.
fn top(&self) -> Self { fn top(&self) -> Self {
Self::new(self.get_address_bytesize()) Self::new(self.get_address_bytesize())
} }
} }
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegion<T> { impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> MemRegion<T> {
// Create a new, empty memory region. // Create a new, empty memory region.
pub fn new(address_bytesize: ByteSize) -> Self { pub fn new(address_bytesize: ByteSize) -> Self {
MemRegion(Arc::new(MemRegionData::new(address_bytesize))) MemRegion(Arc::new(MemRegionData::new(address_bytesize)))
...@@ -66,12 +65,12 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegi ...@@ -66,12 +65,12 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegi
/// The internal data of a memory region. See the description of `MemRegion` for more. /// The internal data of a memory region. See the description of `MemRegion` for more.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct MemRegionData<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> { pub struct MemRegionData<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> {
address_bytesize: ByteSize, address_bytesize: ByteSize,
values: BTreeMap<i64, T>, values: BTreeMap<i64, T>,
} }
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegionData<T> { impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> MemRegionData<T> {
/// create a new, empty MemRegion /// create a new, empty MemRegion
pub fn new(address_bytesize: ByteSize) -> MemRegionData<T> { pub fn new(address_bytesize: ByteSize) -> MemRegionData<T> {
MemRegionData { MemRegionData {
...@@ -233,6 +232,7 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegi ...@@ -233,6 +232,7 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegi
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::abstract_domain::RegisterDomain;
use crate::bil::Bitvector; use crate::bil::Bitvector;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
...@@ -258,6 +258,10 @@ mod tests { ...@@ -258,6 +258,10 @@ mod tests {
fn bytesize(&self) -> ByteSize { fn bytesize(&self) -> ByteSize {
self.1 self.1
} }
fn new_top(bytesize: ByteSize) -> MockDomain {
MockDomain(0, bytesize)
}
} }
impl HasTop for MockDomain { impl HasTop for MockDomain {
...@@ -267,10 +271,6 @@ mod tests { ...@@ -267,10 +271,6 @@ mod tests {
} }
impl RegisterDomain for MockDomain { impl RegisterDomain for MockDomain {
fn new_top(bytesize: ByteSize) -> MockDomain {
MockDomain(0, bytesize)
}
fn bin_op(&self, _op: BinOpType, _rhs: &Self) -> Self { fn bin_op(&self, _op: BinOpType, _rhs: &Self) -> Self {
Self::new_top(self.1) Self::new_top(self.1)
} }
......
...@@ -37,6 +37,10 @@ pub trait AbstractDomain: Sized + Eq + Clone { ...@@ -37,6 +37,10 @@ pub trait AbstractDomain: Sized + Eq + Clone {
pub trait HasByteSize { pub trait HasByteSize {
/// Return the size of the represented value in bytes. /// Return the size of the represented value in bytes.
fn bytesize(&self) -> ByteSize; fn bytesize(&self) -> ByteSize;
/// Return a new top element with the given bytesize.
/// The function is expected to panic if the type in question does not also implement the `HasTop` trait.
fn new_top(bytesize: ByteSize) -> Self;
} }
/// An abstract domain implementing this trait has a global maximum, i.e. a *Top* element. /// An abstract domain implementing this trait has a global maximum, i.e. a *Top* element.
...@@ -55,9 +59,6 @@ pub trait HasTop { ...@@ -55,9 +59,6 @@ pub trait HasTop {
/// The domain is parametrized by its bytesize (which represents the size of the register). /// The domain is parametrized by its bytesize (which represents the size of the register).
/// It has a *Top* element, which is only characterized by its bytesize. /// It has a *Top* element, which is only characterized by its bytesize.
pub trait RegisterDomain: AbstractDomain + HasByteSize + HasTop { pub trait RegisterDomain: AbstractDomain + HasByteSize + HasTop {
/// Return a new top element with the given bytesize
fn new_top(bytesize: ByteSize) -> Self;
/// Compute the (abstract) result of a binary operation /// Compute the (abstract) result of a binary operation
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self; fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self;
......
...@@ -48,6 +48,11 @@ impl<T: RegisterDomain> HasByteSize for PointerDomain<T> { ...@@ -48,6 +48,11 @@ impl<T: RegisterDomain> HasByteSize for PointerDomain<T> {
.expect("Pointer without targets encountered") .expect("Pointer without targets encountered")
.bytesize() .bytesize()
} }
/// PointerDomain has no explicit `Top` element, thus calling this function will panic.
fn new_top(_bytesize: ByteSize) -> Self {
panic!()
}
} }
impl<T: RegisterDomain> PointerDomain<T> { impl<T: RegisterDomain> PointerDomain<T> {
......
...@@ -52,6 +52,11 @@ impl HasByteSize for Taint { ...@@ -52,6 +52,11 @@ impl HasByteSize for Taint {
Self::Tainted(size) | Self::Top(size) => *size, Self::Tainted(size) | Self::Top(size) => *size,
} }
} }
/// Get a new `Top`-value with the given bytesize.
fn new_top(bytesize: ByteSize) -> Self {
Self::Top(bytesize)
}
} }
impl HasTop for Taint { impl HasTop for Taint {
...@@ -62,11 +67,6 @@ impl HasTop for Taint { ...@@ -62,11 +67,6 @@ impl HasTop for Taint {
} }
impl RegisterDomain for Taint { impl RegisterDomain for Taint {
/// Get a new `Top`-value with the given bytesize.
fn new_top(bytesize: ByteSize) -> Self {
Self::Top(bytesize)
}
/// The result of a binary operation is tainted if at least one input value was tainted. /// The result of a binary operation is tainted if at least one input value was tainted.
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self { fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self {
match (self, rhs) { match (self, rhs) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment