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 {
Value(bitvec) => bitvec.width().into(),
}
}
}
impl RegisterDomain for BitvectorDomain {
/// Get a *Top* element with the given bitsize.
fn new_top(bytesize: ByteSize) -> BitvectorDomain {
BitvectorDomain::Top(bytesize)
}
}
impl RegisterDomain for BitvectorDomain {
/// Evaluate the given binary operation.
///
/// 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> {
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> {
......@@ -82,11 +87,6 @@ impl<T: RegisterDomain> HasTop 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
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self {
use BinOpType::*;
......
use super::{AbstractDomain, HasByteSize, HasTop, RegisterDomain};
use super::{AbstractDomain, HasByteSize, HasTop};
use crate::bil::Bitvector;
use crate::intermediate_representation::ByteSize;
use apint::{Int, Width};
......@@ -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.
///
/// 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.
/// Offsets are internally saved as signed integers, which allows negative offsets,
/// e.g. for downward growing stack frames.
......@@ -21,19 +22,17 @@ use std::sync::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)]
#[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>>,
);
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> {
Arc::make_mut(&mut self.0)
}
}
impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> AbstractDomain
for MemRegion<T>
{
impl<T: AbstractDomain + HasByteSize + HasTop + std::fmt::Debug> AbstractDomain for MemRegion<T> {
/// Short-circuting the `MemRegionData::merge` function if `self==other`,
/// to prevent unneccessary cloning.
fn merge(&self, other: &Self) -> Self {
......@@ -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.
fn top(&self) -> Self {
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.
pub fn new(address_bytesize: ByteSize) -> Self {
MemRegion(Arc::new(MemRegionData::new(address_bytesize)))
......@@ -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.
#[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,
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
pub fn new(address_bytesize: ByteSize) -> MemRegionData<T> {
MemRegionData {
......@@ -233,6 +232,7 @@ impl<T: AbstractDomain + HasByteSize + RegisterDomain + std::fmt::Debug> MemRegi
#[cfg(test)]
mod tests {
use super::*;
use crate::abstract_domain::RegisterDomain;
use crate::bil::Bitvector;
use crate::intermediate_representation::*;
......@@ -258,6 +258,10 @@ mod tests {
fn bytesize(&self) -> ByteSize {
self.1
}
fn new_top(bytesize: ByteSize) -> MockDomain {
MockDomain(0, bytesize)
}
}
impl HasTop for MockDomain {
......@@ -267,10 +271,6 @@ mod tests {
}
impl RegisterDomain for MockDomain {
fn new_top(bytesize: ByteSize) -> MockDomain {
MockDomain(0, bytesize)
}
fn bin_op(&self, _op: BinOpType, _rhs: &Self) -> Self {
Self::new_top(self.1)
}
......
......@@ -37,6 +37,10 @@ pub trait AbstractDomain: Sized + Eq + Clone {
pub trait HasByteSize {
/// Return the size of the represented value in bytes.
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.
......@@ -55,9 +59,6 @@ pub trait HasTop {
/// 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.
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
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self;
......
......@@ -48,6 +48,11 @@ impl<T: RegisterDomain> HasByteSize for PointerDomain<T> {
.expect("Pointer without targets encountered")
.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> {
......
......@@ -52,6 +52,11 @@ impl HasByteSize for Taint {
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 {
......@@ -62,11 +67,6 @@ impl HasTop 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.
fn bin_op(&self, op: BinOpType, rhs: &Self) -> Self {
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