Unverified Commit 0d2777b0 by Enkelmann Committed by GitHub

Add Clippy and Rust fmt to CI-pipeline (#75)

parent 7e992eea
#!/bin/bash #!/bin/bash
docker run --rm -t cwe-checker cargo test && docker run --rm -t cwe-checker dune runtest && pytest docker run --rm -t cwe-checker make codestyle-check \
&& docker run --rm -t cwe-checker cargo test \
&& docker run --rm -t cwe-checker dune runtest \
&& pytest
...@@ -18,6 +18,10 @@ test: ...@@ -18,6 +18,10 @@ test:
cd test/artificial_samples; scons; cd ../.. cd test/artificial_samples; scons; cd ../..
pytest -v --ignore=_build pytest -v --ignore=_build
codestyle-check:
cargo fmt -- --check
cargo clippy -- -D clippy::all
clean: clean:
cargo clean cargo clean
rm -f src/libcwe_checker_rs.a rm -f src/libcwe_checker_rs.a
......
...@@ -14,6 +14,7 @@ petgraph = { version = "0.5", features = ["default", "serde-1"] } ...@@ -14,6 +14,7 @@ petgraph = { version = "0.5", features = ["default", "serde-1"] }
fnv = "1.0" # a faster hash function for small keys like integers fnv = "1.0" # a faster hash function for small keys like integers
anyhow = "1.0" # for easy error types anyhow = "1.0" # for easy error types
crossbeam-channel = "0.4" crossbeam-channel = "0.4"
derive_more = "0.99"
[lib] [lib]
name = "cwe_checker_rs" name = "cwe_checker_rs"
......
...@@ -95,7 +95,7 @@ impl<'a> GraphBuilder<'a> { ...@@ -95,7 +95,7 @@ impl<'a> GraphBuilder<'a> {
/// add all subs to the jump targets so that call instructions can be linked to the starting block of the corresponding sub. /// add all subs to the jump targets so that call instructions can be linked to the starting block of the corresponding sub.
fn add_subs_to_jump_targets(&mut self) { fn add_subs_to_jump_targets(&mut self) {
for sub in self.program.term.subs.iter() { for sub in self.program.term.subs.iter() {
if sub.term.blocks.len() > 0 { if !sub.term.blocks.is_empty() {
let start_block = &sub.term.blocks[0]; let start_block = &sub.term.blocks[0];
let target_index = self.jump_targets[&start_block.tid]; let target_index = self.jump_targets[&start_block.tid];
self.jump_targets.insert(sub.tid.clone(), target_index); self.jump_targets.insert(sub.tid.clone(), target_index);
...@@ -140,7 +140,7 @@ impl<'a> GraphBuilder<'a> { ...@@ -140,7 +140,7 @@ impl<'a> GraphBuilder<'a> {
self.return_addresses self.return_addresses
.entry(target_tid.clone()) .entry(target_tid.clone())
.and_modify(|vec| vec.push((source, return_index))) .and_modify(|vec| vec.push((source, return_index)))
.or_insert(vec![(source, return_index)]); .or_insert_with(|| vec![(source, return_index)]);
} }
// TODO: Non-returning calls and tail calls both have no return target in BAP. // TODO: Non-returning calls and tail calls both have no return target in BAP.
// Thus we need to distinguish them somehow to correctly handle tail calls. // Thus we need to distinguish them somehow to correctly handle tail calls.
...@@ -189,8 +189,7 @@ impl<'a> GraphBuilder<'a> { ...@@ -189,8 +189,7 @@ impl<'a> GraphBuilder<'a> {
.term .term
.jmps .jmps
.iter() .iter()
.filter(|jump| matches!(jump.term.kind, JmpKind::Call(_))) .find(|jump| matches!(jump.term.kind, JmpKind::Call(_)))
.next()
.unwrap(); .unwrap();
let cr_combine_node = self.graph.add_node(Node::CallReturn(call_block)); let cr_combine_node = self.graph.add_node(Node::CallReturn(call_block));
self.graph self.graph
...@@ -210,8 +209,7 @@ impl<'a> GraphBuilder<'a> { ...@@ -210,8 +209,7 @@ impl<'a> GraphBuilder<'a> {
.term .term
.jmps .jmps
.iter() .iter()
.find(|jmp| matches!(jmp.term.kind, JmpKind::Return(_))) .any(|jmp| matches!(jmp.term.kind, JmpKind::Return(_)))
.is_some()
{ {
let return_from_node = self.jump_targets[&block.tid].1; let return_from_node = self.jump_targets[&block.tid].1;
self.add_call_return_node_and_edges(sub, return_from_node); self.add_call_return_node_and_edges(sub, return_from_node);
...@@ -242,7 +240,7 @@ impl<'a> GraphBuilder<'a> { ...@@ -242,7 +240,7 @@ impl<'a> GraphBuilder<'a> {
/// This function builds the interprocedural control flow graph for a program term. /// This function builds the interprocedural control flow graph for a program term.
pub fn get_program_cfg(program: &Term<Program>, extern_subs: HashSet<Tid>) -> Graph { pub fn get_program_cfg(program: &Term<Program>, extern_subs: HashSet<Tid>) -> Graph {
let builder = GraphBuilder::new(program, extern_subs); let builder = GraphBuilder::new(program, extern_subs);
return builder.build(); builder.build()
} }
/// For a given set of block TIDs generate a map from the TIDs to the indices of the BlkStart and BlkEnd nodes /// For a given set of block TIDs generate a map from the TIDs to the indices of the BlkStart and BlkEnd nodes
...@@ -255,17 +253,14 @@ pub fn get_indices_of_block_nodes<'a, I: Iterator<Item = &'a Tid>>( ...@@ -255,17 +253,14 @@ pub fn get_indices_of_block_nodes<'a, I: Iterator<Item = &'a Tid>>(
let mut tid_to_indices_map = HashMap::new(); let mut tid_to_indices_map = HashMap::new();
for node_index in graph.node_indices() { for node_index in graph.node_indices() {
if let Some(tid) = tids.get(&graph[node_index].get_block().tid) { if let Some(tid) = tids.get(&graph[node_index].get_block().tid) {
match graph[node_index] { if let Node::BlkStart(_block_term) = graph[node_index] {
Node::BlkStart(_block_term) => { let start_index = node_index;
let start_index = node_index; let end_index = graph.neighbors(start_index).next().unwrap();
let end_index = graph.neighbors(start_index).next().unwrap(); tid_to_indices_map.insert(tid.clone(), (start_index, end_index));
tid_to_indices_map.insert(tid.clone(), (start_index, end_index));
}
_ => (),
} }
} }
} }
return tid_to_indices_map; tid_to_indices_map
} }
#[cfg(test)] #[cfg(test)]
......
...@@ -172,11 +172,11 @@ impl<'a, T: Problem<'a>> GeneralFPProblem for GeneralizedProblem<'a, T> { ...@@ -172,11 +172,11 @@ impl<'a, T: Problem<'a>> GeneralFPProblem for GeneralizedProblem<'a, T> {
Edge::ExternCallStub(call) => self Edge::ExternCallStub(call) => self
.problem .problem
.update_call_stub(node_value.unwrap_value(), call) .update_call_stub(node_value.unwrap_value(), call)
.map(|val| NodeValue::Value(val)), .map(NodeValue::Value),
Edge::Jump(jump, untaken_conditional) => self Edge::Jump(jump, untaken_conditional) => self
.problem .problem
.update_jump(node_value.unwrap_value(), jump, *untaken_conditional) .update_jump(node_value.unwrap_value(), jump, *untaken_conditional)
.map(|val| NodeValue::Value(val)), .map(NodeValue::Value),
} }
} }
} }
...@@ -192,7 +192,7 @@ impl<'a, T: Problem<'a>> Computation<'a, T> { ...@@ -192,7 +192,7 @@ impl<'a, T: Problem<'a>> Computation<'a, T> {
let generalized_problem = GeneralizedProblem::new(problem); let generalized_problem = GeneralizedProblem::new(problem);
let computation = super::fixpoint::Computation::new( let computation = super::fixpoint::Computation::new(
generalized_problem, generalized_problem,
default_value.map(|val| NodeValue::Value(val)), default_value.map(NodeValue::Value),
); );
Computation { Computation {
generalized_computation: computation, generalized_computation: computation,
......
...@@ -21,8 +21,10 @@ Implementation needs is_top() to be a member function of the ValueDomain trait. ...@@ -21,8 +21,10 @@ Implementation needs is_top() to be a member function of the ValueDomain trait.
use super::abstract_domain::*; use super::abstract_domain::*;
use crate::bil::{BitSize, Bitvector}; use crate::bil::{BitSize, Bitvector};
use apint::{Int, Width}; use apint::{Int, Width};
use derive_more::Deref;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ops::DerefMut;
use std::sync::Arc; use std::sync::Arc;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
...@@ -31,21 +33,17 @@ struct Element<T> { ...@@ -31,21 +33,17 @@ struct Element<T> {
value: T, value: T,
} }
#[derive(Serialize, Deserialize, Debug, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, Hash, Clone, PartialEq, Eq, Deref)]
#[deref(forward)]
pub struct MemRegion<T: AbstractDomain + ValueDomain + std::fmt::Debug>(Arc<MemRegionData<T>>); pub struct MemRegion<T: AbstractDomain + ValueDomain + std::fmt::Debug>(Arc<MemRegionData<T>>);
impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> PartialEq for MemRegion<T> { impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> DerefMut for MemRegion<T> {
fn eq(&self, other: &Self) -> bool { fn deref_mut(&mut self) -> &mut MemRegionData<T> {
if Arc::ptr_eq(&self.0, &other.0) { Arc::make_mut(&mut self.0)
true
} else {
self.0 == other.0
}
} }
} }
impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> Eq for MemRegion<T> {} // TODO: most of the functions in this impl block should be moved to MemRegionData (or removed, if they are only thin wrappers).
impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegion<T> { impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegion<T> {
pub fn new(address_bitsize: BitSize) -> Self { pub fn new(address_bitsize: BitSize) -> Self {
MemRegion(Arc::new(MemRegionData::new(address_bitsize))) MemRegion(Arc::new(MemRegionData::new(address_bitsize)))
...@@ -90,7 +88,7 @@ impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegion<T> { ...@@ -90,7 +88,7 @@ impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegion<T> {
/// An abstract domain representing a continuous region of memory. See the module level description for more. /// An abstract domain representing a continuous region of memory. See the module level description for more.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
struct MemRegionData<T: AbstractDomain + ValueDomain + std::fmt::Debug> { pub struct MemRegionData<T: AbstractDomain + ValueDomain + std::fmt::Debug> {
address_bitsize: BitSize, address_bitsize: BitSize,
values: BTreeMap<i64, T>, values: BTreeMap<i64, T>,
} }
...@@ -162,7 +160,7 @@ impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegionData<T> { ...@@ -162,7 +160,7 @@ impl<T: AbstractDomain + ValueDomain + std::fmt::Debug> MemRegionData<T> {
} }
} }
let bitsize = 8 * size as u16; let bitsize = 8 * size as u16;
return T::new_top(bitsize); T::new_top(bitsize)
} }
/// Remove all elements intersecting the provided interval. /// Remove all elements intersecting the provided interval.
......
...@@ -166,7 +166,6 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -166,7 +166,6 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
} else { } else {
panic!("Malformed control flow graph: Encountered call edge with a non-call jump term.") panic!("Malformed control flow graph: Encountered call edge with a non-call jump term.")
}; };
let stack_offset_domain = self.get_current_stack_offset(state);
if let Label::Direct(ref callee_tid) = call.target { if let Label::Direct(ref callee_tid) = call.target {
let callee_stack_id = AbstractIdentifier::new( let callee_stack_id = AbstractIdentifier::new(
...@@ -177,7 +176,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -177,7 +176,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
call_term.tid.clone(), call_term.tid.clone(),
AbstractLocation::from_var(&self.project.stack_pointer_register).unwrap(), AbstractLocation::from_var(&self.project.stack_pointer_register).unwrap(),
); );
let stack_offset_adjustment = stack_offset_domain.clone(); let stack_offset_adjustment = self.get_current_stack_offset(state);
let address_bitsize = self.project.stack_pointer_register.bitsize().unwrap(); let address_bitsize = self.project.stack_pointer_register.bitsize().unwrap();
let mut callee_state = state.clone(); let mut callee_state = state.clone();
...@@ -214,9 +213,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -214,9 +213,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
); );
// set the list of caller stack ids to only this caller id // set the list of caller stack ids to only this caller id
callee_state.caller_stack_ids = BTreeSet::new(); callee_state.caller_stack_ids = BTreeSet::new();
callee_state callee_state.caller_stack_ids.insert(new_caller_stack_id);
.caller_stack_ids
.insert(new_caller_stack_id.clone());
// Remove non-referenced objects and objects, only the caller knows about, from the state. // Remove non-referenced objects and objects, only the caller knows about, from the state.
callee_state.ids_known_to_caller = BTreeSet::new(); callee_state.ids_known_to_caller = BTreeSet::new();
callee_state.remove_unreferenced_objects(); callee_state.remove_unreferenced_objects();
...@@ -224,7 +221,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -224,7 +221,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
callee_state.ids_known_to_caller = callee_state.memory.get_all_object_ids(); callee_state.ids_known_to_caller = callee_state.memory.get_all_object_ids();
callee_state.ids_known_to_caller.remove(&callee_stack_id); callee_state.ids_known_to_caller.remove(&callee_stack_id);
return callee_state; callee_state
} else { } else {
panic!("Indirect call edges not yet supported.") panic!("Indirect call edges not yet supported.")
// TODO: Support indirect call edges! // TODO: Support indirect call edges!
...@@ -277,7 +274,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -277,7 +274,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
state_after_return.merge_callee_stack_to_caller_stack( state_after_return.merge_callee_stack_to_caller_stack(
callee_stack_id, callee_stack_id,
original_caller_stack_id, original_caller_stack_id,
&(-stack_offset_on_call.clone()), &(-stack_offset_on_call),
); );
state_after_return.stack_id = original_caller_stack_id.clone(); state_after_return.stack_id = original_caller_stack_id.clone();
state_after_return.caller_stack_ids = state_before_call.caller_stack_ids.clone(); state_after_return.caller_stack_ids = state_before_call.caller_stack_ids.clone();
...@@ -382,11 +379,11 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -382,11 +379,11 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
new_state.set_register(return_register, pointer.into()), new_state.set_register(return_register, pointer.into()),
Some(&call.tid), Some(&call.tid),
); );
return Some(new_state); Some(new_state)
} else { } else {
// We cannot track the new object, since we do not know where to store the pointer to it. // We cannot track the new object, since we do not know where to store the pointer to it.
// TODO: Return a diagnostics message to the user here. // TODO: Return a diagnostics message to the user here.
return Some(new_state); Some(new_state)
} }
} }
"free" => { "free" => {
...@@ -412,16 +409,16 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -412,16 +409,16 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
} }
} // TODO: add diagnostics for else case } // TODO: add diagnostics for else case
new_state.remove_unreferenced_objects(); new_state.remove_unreferenced_objects();
return Some(new_state); Some(new_state)
} else { } else {
// TODO: add diagnostics message for the user here // TODO: add diagnostics message for the user here
return Some(new_state); Some(new_state)
} }
} }
Err(err) => { Err(err) => {
// We do not know which memory object to free // We do not know which memory object to free
self.log_debug(Err(err), Some(&call.tid)); self.log_debug(Err(err), Some(&call.tid));
return Some(new_state); Some(new_state)
} }
} }
} }
...@@ -431,7 +428,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -431,7 +428,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
Some(&call.tid), Some(&call.tid),
); );
let mut possible_referenced_ids = BTreeSet::new(); let mut possible_referenced_ids = BTreeSet::new();
if extern_symbol.arguments.len() == 0 { if extern_symbol.arguments.is_empty() {
// TODO: We assume here that we do not know the parameters and approximate them by all parameter registers. // TODO: We assume here that we do not know the parameters and approximate them by all parameter registers.
// This approximation is wrong if the function is known but has neither parameters nor return values. // This approximation is wrong if the function is known but has neither parameters nor return values.
// We need to somehow distinguish these two cases. // We need to somehow distinguish these two cases.
...@@ -465,7 +462,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a> ...@@ -465,7 +462,7 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Problem<'a> for Context<'a>
.memory .memory
.mark_mem_object_as_untracked(id, &possible_referenced_ids); .mark_mem_object_as_untracked(id, &possible_referenced_ids);
} }
return Some(new_state); Some(new_state)
} }
} }
} else { } else {
......
...@@ -54,7 +54,7 @@ impl Data { ...@@ -54,7 +54,7 @@ impl Data {
} }
}) })
.collect(); .collect();
if remaining_targets.len() == 0 { if remaining_targets.is_empty() {
*self = Data::new_top(self.bitsize()); *self = Data::new_top(self.bitsize());
} else { } else {
*self = Data::Pointer(PointerDomain::with_targets(remaining_targets)); *self = Data::Pointer(PointerDomain::with_targets(remaining_targets));
......
use crate::bil::variable::*; use crate::bil::variable::*;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::fast_cmp_arc::FastCmpArc; use derive_more::Deref;
use std::sync::Arc; use std::sync::Arc;
// TODO: Right now abstract locations are used as giving the location where a pointer to an object is located. // TODO: Right now abstract locations are used as giving the location where a pointer to an object is located.
...@@ -14,8 +14,10 @@ use std::sync::Arc; ...@@ -14,8 +14,10 @@ use std::sync::Arc;
/// The time identifier is given by a `Tid`. /// The time identifier is given by a `Tid`.
/// If it is the Tid of a basic block, then it describes the point in time *before* execution of the first instruction in the block. /// If it is the Tid of a basic block, then it describes the point in time *before* execution of the first instruction in the block.
/// If it is the Tid of a Def or Jmp, then it describes the point in time *after* the execution of the Def or Jmp. /// If it is the Tid of a Def or Jmp, then it describes the point in time *after* the execution of the Def or Jmp.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
pub struct AbstractIdentifier(FastCmpArc<AbstractIdentifierData>); #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord, Deref)]
#[deref(forward)]
pub struct AbstractIdentifier(Arc<AbstractIdentifierData>);
/// The data contained in an abstract identifier /// The data contained in an abstract identifier
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
...@@ -27,10 +29,7 @@ pub struct AbstractIdentifierData { ...@@ -27,10 +29,7 @@ pub struct AbstractIdentifierData {
impl AbstractIdentifier { impl AbstractIdentifier {
/// create a new abstract identifier /// create a new abstract identifier
pub fn new(time: Tid, location: AbstractLocation) -> AbstractIdentifier { pub fn new(time: Tid, location: AbstractLocation) -> AbstractIdentifier {
AbstractIdentifier(FastCmpArc(Arc::new(AbstractIdentifierData { AbstractIdentifier(Arc::new(AbstractIdentifierData { time, location }))
time,
location,
})))
} }
} }
......
...@@ -55,7 +55,7 @@ impl<'a> PointerInference<'a> { ...@@ -55,7 +55,7 @@ impl<'a> PointerInference<'a> {
if let Some((start_node_index, _end_node_index)) = if let Some((start_node_index, _end_node_index)) =
tid_to_graph_indices_map.get(&block_tid) tid_to_graph_indices_map.get(&block_tid)
{ {
Some((sub_tid.clone(), start_node_index.clone())) Some((sub_tid.clone(), *start_node_index))
} else { } else {
None None
} }
...@@ -147,8 +147,7 @@ impl<'a> PointerInference<'a> { ...@@ -147,8 +147,7 @@ impl<'a> PointerInference<'a> {
.term .term
.extern_symbols .extern_symbols
.iter() .iter()
.find(|symbol| symbol.tid == sub.tid) .any(|symbol| symbol.tid == sub.tid)
.is_some()
{ {
continue; // We ignore functions marked as extern symbols. continue; // We ignore functions marked as extern symbols.
} }
...@@ -160,19 +159,15 @@ impl<'a> PointerInference<'a> { ...@@ -160,19 +159,15 @@ impl<'a> PointerInference<'a> {
let mut new_entry_points = Vec::new(); let mut new_entry_points = Vec::new();
for (node_id, node) in graph.node_references() { for (node_id, node) in graph.node_references() {
if let Node::BlkStart(block) = node { if let Node::BlkStart(block) = node {
if start_block_to_sub_map.get(&block.tid).is_some() if !(start_block_to_sub_map.get(&block.tid).is_none()
&& self.computation.get_node_value(node_id).is_none() || self.computation.get_node_value(node_id).is_some()
{ || only_cfg_roots
if only_cfg_roots
&& graph && graph
.neighbors_directed(node_id, Direction::Incoming) .neighbors_directed(node_id, Direction::Incoming)
.next() .next()
.is_none() .is_some())
{ {
new_entry_points.push(node_id); new_entry_points.push(node_id);
} else if !only_cfg_roots {
new_entry_points.push(node_id);
}
} }
} }
} }
......
...@@ -210,7 +210,7 @@ impl AbstractObjectInfo { ...@@ -210,7 +210,7 @@ impl AbstractObjectInfo {
} else { } else {
self.memory = MemRegion::new(self.memory.get_address_bitsize()); self.memory = MemRegion::new(self.memory.get_address_bitsize());
} }
return Ok(()); Ok(())
} }
fn get_all_possible_pointer_targets(&self) -> BTreeSet<AbstractIdentifier> { fn get_all_possible_pointer_targets(&self) -> BTreeSet<AbstractIdentifier> {
...@@ -222,7 +222,7 @@ impl AbstractObjectInfo { ...@@ -222,7 +222,7 @@ impl AbstractObjectInfo {
} }
}; };
} }
return targets; targets
} }
/// For pointer values replace an abstract identifier with another one and add the offset_adjustment to the pointer offsets. /// For pointer values replace an abstract identifier with another one and add the offset_adjustment to the pointer offsets.
...@@ -245,11 +245,9 @@ impl AbstractObjectInfo { ...@@ -245,11 +245,9 @@ impl AbstractObjectInfo {
pub fn set_state(&mut self, new_state: Option<ObjectState>) { pub fn set_state(&mut self, new_state: Option<ObjectState>) {
if self.is_unique { if self.is_unique {
self.state = new_state; self.state = new_state;
} else { } else if self.state != new_state {
if self.state != new_state { self.state = None;
self.state = None; } // else don't change the state
} // else don't change the state
}
} }
/// Remove the provided IDs from the target lists of all pointers in the memory object. /// Remove the provided IDs from the target lists of all pointers in the memory object.
......
...@@ -55,7 +55,7 @@ impl AbstractObjectList { ...@@ -55,7 +55,7 @@ impl AbstractObjectList {
} }
} }
} }
return false; false
} }
/// Get the value at a given address. /// Get the value at a given address.
...@@ -87,7 +87,7 @@ impl AbstractObjectList { ...@@ -87,7 +87,7 @@ impl AbstractObjectList {
break; break;
} }
} }
merged_value.ok_or(anyhow!("Pointer without targets encountered.")) merged_value.ok_or_else(|| anyhow!("Pointer without targets encountered."))
} }
} }
} }
...@@ -102,7 +102,7 @@ impl AbstractObjectList { ...@@ -102,7 +102,7 @@ impl AbstractObjectList {
for (id, _offset) in pointer.iter_targets() { for (id, _offset) in pointer.iter_targets() {
target_object_set.insert(self.ids.get(id).unwrap().0); target_object_set.insert(self.ids.get(id).unwrap().0);
} }
if target_object_set.len() == 0 { if target_object_set.is_empty() {
return Err(anyhow!("Pointer without targets encountered")); return Err(anyhow!("Pointer without targets encountered"));
} }
if target_object_set.len() == 1 { if target_object_set.len() == 1 {
...@@ -170,7 +170,7 @@ impl AbstractObjectList { ...@@ -170,7 +170,7 @@ impl AbstractObjectList {
let mut merged_objects = self.objects.clone(); let mut merged_objects = self.objects.clone();
let mut merged_ids = self.ids.clone(); let mut merged_ids = self.ids.clone();
for (other_id, (other_index, other_offset)) in other.ids.iter() { for (other_id, (other_index, other_offset)) in other.ids.iter() {
if let Some((index, offset)) = merged_ids.get(&other_id).clone() { if let Some((index, offset)) = merged_ids.get(&other_id) {
let (index, offset) = (*index, offset.clone()); let (index, offset) = (*index, offset.clone());
merged_ids.insert(other_id.clone(), (index, offset.merge(&other_offset))); merged_ids.insert(other_id.clone(), (index, offset.merge(&other_offset)));
if index < self.objects.len() { if index < self.objects.len() {
...@@ -322,24 +322,22 @@ impl AbstractObjectList { ...@@ -322,24 +322,22 @@ impl AbstractObjectList {
} }
Arc::make_mut(object).set_state(None); Arc::make_mut(object).set_state(None);
} }
} else { } else if let Some(id) = ids.iter().next() {
if let Some(id) = ids.iter().next() { let object = &mut self.objects[self.ids[&id].0];
let object = &mut self.objects[self.ids[&id].0]; if let AbstractObject::Memory(tracked_mem) = Arc::deref(object) {
if let AbstractObject::Memory(tracked_mem) = Arc::deref(object) { if tracked_mem.state != Some(ObjectState::Alive) {
if tracked_mem.state != Some(ObjectState::Alive) { // Possible double free detected
// Possible double free detected // TODO: Check rate of false positives.
// TODO: Check rate of false positives. // If too high, only mark those with explicit dangling state.
// If too high, only mark those with explicit dangling state. possible_double_free_ids.push(id.clone());
possible_double_free_ids.push(id.clone());
}
} }
Arc::make_mut(object).set_state(Some(ObjectState::Dangling));
} }
Arc::make_mut(object).set_state(Some(ObjectState::Dangling));
} }
if possible_double_free_ids.is_empty() { if possible_double_free_ids.is_empty() {
return Ok(()); Ok(())
} else { } else {
return Err(possible_double_free_ids); Err(possible_double_free_ids)
} }
} }
...@@ -380,11 +378,10 @@ impl AbstractObjectList { ...@@ -380,11 +378,10 @@ impl AbstractObjectList {
} }
} }
let mut old_to_new_index_map: BTreeMap<usize, usize> = BTreeMap::new(); let mut old_to_new_index_map: BTreeMap<usize, usize> = BTreeMap::new();
for old_index in 0..other_object_list.objects.len() { for (old_index, old_object) in other_object_list.objects.iter().enumerate() {
if objects_already_known[old_index] == false { if !objects_already_known[old_index] {
old_to_new_index_map.insert(old_index, self.objects.len()); old_to_new_index_map.insert(old_index, self.objects.len());
self.objects self.objects.push(old_object.clone());
.push(other_object_list.objects[old_index].clone());
} }
} }
for (id, (old_index, offset)) in other_object_list.ids.iter() { for (id, (old_index, offset)) in other_object_list.ids.iter() {
......
...@@ -98,7 +98,7 @@ impl State { ...@@ -98,7 +98,7 @@ impl State {
} }
Ok(()) Ok(())
} else { } else {
return Err(anyhow!("Variable is not a register type")); Err(anyhow!("Variable is not a register type"))
} }
} }
...@@ -138,8 +138,7 @@ impl State { ...@@ -138,8 +138,7 @@ impl State {
.filter_map(|(register, value)| { .filter_map(|(register, value)| {
if callee_saved_register_names if callee_saved_register_names
.iter() .iter()
.find(|reg_name| **reg_name == register.name) .any(|reg_name| **reg_name == register.name)
.is_some()
{ {
Some((register.clone(), value.clone())) Some((register.clone(), value.clone()))
} else { } else {
...@@ -284,11 +283,11 @@ impl State { ...@@ -284,11 +283,11 @@ impl State {
// A more precise solution would write to every caller memory region separately, // A more precise solution would write to every caller memory region separately,
// but would also need to check first whether the target memory region is unique or not. // but would also need to check first whether the target memory region is unique or not.
self.memory.set_value(pointer, value.clone())?; self.memory.set_value(pointer, value.clone())?;
return Ok(()); Ok(())
} else { } else {
// TODO: Implement recognition of stores to global memory. // TODO: Implement recognition of stores to global memory.
// Needs implementation of reads from global data first. // Needs implementation of reads from global data first.
return Err(anyhow!("Memory write to non-pointer data")); Err(anyhow!("Memory write to non-pointer data"))
} }
} }
...@@ -313,10 +312,10 @@ impl State { ...@@ -313,10 +312,10 @@ impl State {
size, size,
} = store_exp } = store_exp
{ {
let data = self.eval(value).unwrap_or(Data::new_top(*size)); let data = self.eval(value).unwrap_or_else(|_| Data::new_top(*size));
assert_eq!(data.bitsize(), *size); assert_eq!(data.bitsize(), *size);
// TODO: At the moment, both memory and endianness are ignored. Change that! // TODO: At the moment, both memory and endianness are ignored. Change that!
return self.write_to_address(address, &data); self.write_to_address(address, &data)
} else { } else {
panic!("Expected store expression") panic!("Expected store expression")
} }
...@@ -343,7 +342,7 @@ impl State { ...@@ -343,7 +342,7 @@ impl State {
} }
} }
// We only return the last error encountered. // We only return the last error encountered.
return result_log; result_log
} }
/// merge two states /// merge two states
...@@ -353,7 +352,7 @@ impl State { ...@@ -353,7 +352,7 @@ impl State {
for (register, other_value) in other.register.iter() { for (register, other_value) in other.register.iter() {
if let Some(value) = self.register.get(register) { if let Some(value) = self.register.get(register) {
let merged_value = value.merge(other_value); let merged_value = value.merge(other_value);
if merged_value.is_top() == false { if !merged_value.is_top() {
// We only have to keep non-top elements. // We only have to keep non-top elements.
merged_register.insert(register.clone(), merged_value); merged_register.insert(register.clone(), merged_value);
} }
...@@ -393,7 +392,7 @@ impl State { ...@@ -393,7 +392,7 @@ impl State {
match offset { match offset {
BitvectorDomain::Value(offset_val) => { BitvectorDomain::Value(offset_val) => {
if offset_val.try_to_i64().unwrap() >= 0 if offset_val.try_to_i64().unwrap() >= 0
&& self.caller_stack_ids.len() > 0 && !self.caller_stack_ids.is_empty()
{ {
for caller_id in self.caller_stack_ids.iter() { for caller_id in self.caller_stack_ids.iter() {
new_targets.add_target(caller_id.clone(), offset.clone()); new_targets.add_target(caller_id.clone(), offset.clone());
...@@ -415,9 +414,9 @@ impl State { ...@@ -415,9 +414,9 @@ impl State {
new_targets.add_target(id.clone(), offset.clone()); new_targets.add_target(id.clone(), offset.clone());
} }
} }
return Data::Pointer(new_targets); Data::Pointer(new_targets)
} else { } else {
return address.clone(); address.clone()
} }
} }
...@@ -486,7 +485,7 @@ impl State { ...@@ -486,7 +485,7 @@ impl State {
} }
} }
} }
return ids; ids
} }
/// Merge the callee stack with the caller stack. /// Merge the callee stack with the caller stack.
...@@ -531,7 +530,7 @@ impl State { ...@@ -531,7 +530,7 @@ impl State {
.register .register
.clone() .clone()
.into_iter() .into_iter()
.filter(|(register, _value)| register.is_temp == false) .filter(|(register, _value)| !register.is_temp)
.collect(); .collect();
} }
......
...@@ -15,12 +15,12 @@ fn run_pointer_inference(program_jsonbuilder_val: ocaml::Value) -> (Vec<CweWarni ...@@ -15,12 +15,12 @@ fn run_pointer_inference(program_jsonbuilder_val: ocaml::Value) -> (Vec<CweWarni
} }
caml!(rs_run_pointer_inference(program_jsonbuilder_val) { caml!(rs_run_pointer_inference(program_jsonbuilder_val) {
return failwith_on_panic( || { failwith_on_panic( || {
let cwe_warnings_and_log = run_pointer_inference(program_jsonbuilder_val); let cwe_warnings_and_log = run_pointer_inference(program_jsonbuilder_val);
let cwe_warnings_and_log_json = serde_json::to_string(&cwe_warnings_and_log).unwrap(); let cwe_warnings_and_log_json = serde_json::to_string(&cwe_warnings_and_log).unwrap();
let ocaml_string = ocaml::Str::from(&cwe_warnings_and_log_json as &str); let ocaml_string = ocaml::Str::from(&cwe_warnings_and_log_json as &str);
ocaml::Value::from(ocaml_string) ocaml::Value::from(ocaml_string)
}); })
}); });
fn run_pointer_inference_and_print_debug(program_jsonbuilder_val: ocaml::Value) { fn run_pointer_inference_and_print_debug(program_jsonbuilder_val: ocaml::Value) {
...@@ -33,8 +33,8 @@ fn run_pointer_inference_and_print_debug(program_jsonbuilder_val: ocaml::Value) ...@@ -33,8 +33,8 @@ fn run_pointer_inference_and_print_debug(program_jsonbuilder_val: ocaml::Value)
} }
caml!(rs_run_pointer_inference_and_print_debug(program_jsonbuilder_val) { caml!(rs_run_pointer_inference_and_print_debug(program_jsonbuilder_val) {
return failwith_on_panic( || { failwith_on_panic( || {
run_pointer_inference_and_print_debug(program_jsonbuilder_val); run_pointer_inference_and_print_debug(program_jsonbuilder_val);
ocaml::Value::unit() ocaml::Value::unit()
}); })
}); });
...@@ -73,10 +73,10 @@ impl From<&JsonBuilder> for serde_json::Value { ...@@ -73,10 +73,10 @@ impl From<&JsonBuilder> for serde_json::Value {
} }
caml!(rs_finalize_json_builder(builder_val) { caml!(rs_finalize_json_builder(builder_val) {
return failwith_on_panic( || { failwith_on_panic( || {
JsonBuilder::ocaml_finalize(builder_val); JsonBuilder::ocaml_finalize(builder_val);
ocaml::Value::unit() ocaml::Value::unit()
}); })
}); });
/// Build JsonBuilder::Null as Ocaml value /// Build JsonBuilder::Null as Ocaml value
...@@ -85,9 +85,9 @@ fn build_serde_null() -> ocaml::Value { ...@@ -85,9 +85,9 @@ fn build_serde_null() -> ocaml::Value {
} }
caml!(rs_build_serde_null(_unit) { caml!(rs_build_serde_null(_unit) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_null() build_serde_null()
}); })
}); });
/// Build JsonBuilder::Bool as Ocaml value /// Build JsonBuilder::Bool as Ocaml value
...@@ -97,9 +97,9 @@ fn build_serde_bool(bool_val: ocaml::Value) -> ocaml::Value { ...@@ -97,9 +97,9 @@ fn build_serde_bool(bool_val: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_build_serde_bool(bool_val) { caml!(rs_build_serde_bool(bool_val) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_bool(bool_val) build_serde_bool(bool_val)
}); })
}); });
/// Build JsonBuilder::Number as Ocaml value /// Build JsonBuilder::Number as Ocaml value
...@@ -109,9 +109,9 @@ fn build_serde_number(num: ocaml::Value) -> ocaml::Value { ...@@ -109,9 +109,9 @@ fn build_serde_number(num: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_build_serde_number(number) { caml!(rs_build_serde_number(number) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_number(number) build_serde_number(number)
}); })
}); });
/// Build JsonBuilder::Object representing a bitvector from a string generated by `Bitvector.to_string` in Ocaml /// Build JsonBuilder::Object representing a bitvector from a string generated by `Bitvector.to_string` in Ocaml
...@@ -127,7 +127,7 @@ fn build_serde_bitvector(bitvector_string_val: ocaml::Value) -> ocaml::Value { ...@@ -127,7 +127,7 @@ fn build_serde_bitvector(bitvector_string_val: ocaml::Value) -> ocaml::Value {
if number_slice.starts_with("0x") { if number_slice.starts_with("0x") {
number_slice = &number_slice[2..]; number_slice = &number_slice[2..];
} }
while number_slice.len() > 0 { while !number_slice.is_empty() {
if number_slice.len() > 16 { if number_slice.len() > 16 {
let digit = u64::from_str_radix(&number_slice[(number_slice.len() - 16)..], 16) let digit = u64::from_str_radix(&number_slice[(number_slice.len() - 16)..], 16)
.expect("Bitvector value parsing failed"); .expect("Bitvector value parsing failed");
...@@ -151,18 +151,14 @@ fn build_serde_bitvector(bitvector_string_val: ocaml::Value) -> ocaml::Value { ...@@ -151,18 +151,14 @@ fn build_serde_bitvector(bitvector_string_val: ocaml::Value) -> ocaml::Value {
("digits".to_string(), Rc::new(JsonBuilder::Array(num_list))), ("digits".to_string(), Rc::new(JsonBuilder::Array(num_list))),
("width".to_string(), Rc::new(JsonBuilder::Array(width_list))), ("width".to_string(), Rc::new(JsonBuilder::Array(width_list))),
]); ]);
// TODO: remove deserialization check
let check_serde = serde_json::to_string(&serde_json::Value::from(&result)).unwrap();
let _bitv: apint::ApInt = serde_json::from_str(&check_serde)
.expect(&format!("Invalid value generated: {}", check_serde));
result.to_ocaml() result.to_ocaml()
} }
caml!(rs_build_serde_bitvector(bitvector_string) { caml!(rs_build_serde_bitvector(bitvector_string) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_bitvector(bitvector_string) build_serde_bitvector(bitvector_string)
}); })
}); });
/// Build JsonBuilder::String as Ocaml value /// Build JsonBuilder::String as Ocaml value
...@@ -172,9 +168,9 @@ fn build_serde_string(string_val: ocaml::Value) -> ocaml::Value { ...@@ -172,9 +168,9 @@ fn build_serde_string(string_val: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_build_serde_string(string_val) { caml!(rs_build_serde_string(string_val) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_string(string_val) build_serde_string(string_val)
}); })
}); });
/// Build JsonBuilder::Array as Ocaml value from an Ocaml list /// Build JsonBuilder::Array as Ocaml value from an Ocaml list
...@@ -189,9 +185,9 @@ fn build_serde_array_from_list(list_val: ocaml::Value) -> ocaml::Value { ...@@ -189,9 +185,9 @@ fn build_serde_array_from_list(list_val: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_build_serde_array_from_list(list_val) { caml!(rs_build_serde_array_from_list(list_val) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_array_from_list(list_val) build_serde_array_from_list(list_val)
}); })
}); });
/// Build JsonBuilder::Object as Ocaml value from an Ocaml list of tuples /// Build JsonBuilder::Object as Ocaml value from an Ocaml list of tuples
...@@ -217,9 +213,9 @@ fn build_serde_object(tuple_list_val: ocaml::Value) -> ocaml::Value { ...@@ -217,9 +213,9 @@ fn build_serde_object(tuple_list_val: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_build_serde_object(tuple_list_val) { caml!(rs_build_serde_object(tuple_list_val) {
return failwith_on_panic( || { failwith_on_panic( || {
build_serde_object(tuple_list_val) build_serde_object(tuple_list_val)
}); })
}); });
/// Get the Json string corresponding to a JsonBuilder object and return it as an Ocaml value. /// Get the Json string corresponding to a JsonBuilder object and return it as an Ocaml value.
...@@ -230,7 +226,7 @@ fn get_json_string(builder_val: ocaml::Value) -> ocaml::Value { ...@@ -230,7 +226,7 @@ fn get_json_string(builder_val: ocaml::Value) -> ocaml::Value {
} }
caml!(rs_convert_json_to_string(builder_val) { caml!(rs_convert_json_to_string(builder_val) {
return failwith_on_panic( || { failwith_on_panic( || {
get_json_string(builder_val) get_json_string(builder_val)
}); })
}); });
...@@ -29,7 +29,7 @@ impl ExternSymbol { ...@@ -29,7 +29,7 @@ impl ExternSymbol {
} }
match &return_args[0].location { match &return_args[0].location {
Expression::Var(var) => Ok(var), Expression::Var(var) => Ok(var),
_ => Err(anyhow!("Return location is not a register"))?, _ => Err(anyhow!("Return location is not a register")),
} }
} }
......
use crate::analysis::abstract_domain::AbstractDomain;
use crate::prelude::*;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
// TODO: This is a helper not only for abstract domains! It needs its own source file!
#[derive(Serialize, Deserialize, Debug, Hash, Clone)]
pub struct FastCmpArc<T>(pub Arc<T>);
impl<T: PartialEq + Eq> PartialEq for FastCmpArc<T> {
fn eq(&self, other: &Self) -> bool {
if Arc::ptr_eq(&self.0, &other.0) {
true
} else {
self.0.eq(&other.0)
}
}
}
impl<T: Eq> Eq for FastCmpArc<T> {}
impl<T: AbstractDomain + Clone> AbstractDomain for FastCmpArc<T> {
fn top(&self) -> Self {
FastCmpArc(Arc::new(self.0.top()))
}
fn merge(&self, other: &Self) -> Self {
if Arc::ptr_eq(&self.0, &other.0) {
self.clone()
} else {
FastCmpArc(Arc::new(self.0.merge(&other.0)))
}
}
}
impl<T: PartialOrd + Ord> PartialOrd for FastCmpArc<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: PartialOrd + Ord> Ord for FastCmpArc<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if Arc::ptr_eq(&self.0, &other.0) {
std::cmp::Ordering::Equal
} else {
self.0.cmp(&other.0)
}
}
}
impl<T> Deref for FastCmpArc<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: Clone> DerefMut for FastCmpArc<T> {
fn deref_mut(&mut self) -> &mut T {
Arc::make_mut(&mut self.0)
}
}
pub mod fast_cmp_arc;
pub mod log; pub mod log;
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