use std::{
collections::{BTreeMap, HashMap},
fmt::Debug,
};
use crate::{
abstract_domain::{AbstractDomain, DomainInsertion, HasTop},
intermediate_representation::Project,
prelude::*,
};
use self::state::State;
use super::{
fixpoint::Computation, forward_interprocedural_fixpoint::GeneralizedContext, graph::Graph,
interprocedural_fixpoint_generic::NodeValue,
pointer_inference::PointerInference as PointerInferenceComputation,
};
pub mod context;
pub mod state;
use context::*;
use petgraph::graph::NodeIndex;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Config {
pub string_symbols: Vec<String>,
pub format_string_index: BTreeMap<String, usize>,
}
pub struct StringAbstraction<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> {
computation: Computation<GeneralizedContext<'a, Context<'a, T>>>,
}
impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
StringAbstraction<'a, T>
{
pub fn new(
project: &'a Project,
control_flow_graph: &'a Graph<'a>,
pointer_inference_results: &'a PointerInferenceComputation<'a>,
config: Config,
) -> StringAbstraction<'a, T> {
let context = Context::new(project, pointer_inference_results, config);
let mut sub_to_entry_blocks_map = HashMap::new();
for sub in project.program.term.subs.values() {
if let Some(entry_block) = sub.term.blocks.first() {
sub_to_entry_blocks_map.insert(sub.tid.clone(), entry_block.tid.clone());
}
}
let mut tid_to_graph_indices_map = HashMap::new();
for node in control_flow_graph.node_indices() {
if let super::graph::Node::BlkStart(block, sub) = control_flow_graph[node] {
tid_to_graph_indices_map.insert((block.tid.clone(), sub.tid.clone()), node);
}
}
let sub_to_entry_node_map: HashMap<Tid, NodeIndex> = sub_to_entry_blocks_map
.into_iter()
.filter_map(|(sub_tid, block_tid)| {
tid_to_graph_indices_map
.get(&(block_tid, sub_tid.clone()))
.map(|start_node_index| (sub_tid, *start_node_index))
})
.collect();
let mut fixpoint_computation =
super::forward_interprocedural_fixpoint::create_computation(context, None);
for (_, start_node_index) in sub_to_entry_node_map.into_iter() {
fixpoint_computation.set_node_value(
start_node_index,
super::interprocedural_fixpoint_generic::NodeValue::Value(State::new(
start_node_index,
pointer_inference_results,
)),
);
}
StringAbstraction {
computation: fixpoint_computation,
}
}
pub fn compute(&mut self) {
self.computation.compute_with_max_steps(100); }
pub fn get_computation(&self) -> &Computation<GeneralizedContext<'a, Context<'a, T>>> {
&self.computation
}
pub fn get_graph(&self) -> &Graph {
self.computation.get_graph()
}
pub fn get_context(&self) -> &Context<'a, T> {
self.computation.get_context().get_context()
}
pub fn get_node_value(&self, node_id: NodeIndex) -> Option<&NodeValue<State<T>>> {
self.computation.get_node_value(node_id)
}
}
pub fn run<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion>(
project: &'a Project,
control_flow_graph: &'a Graph<'a>,
pointer_inference: &'a PointerInferenceComputation<'a>,
config: Config,
) -> StringAbstraction<'a, T> {
let mut string_abstraction =
StringAbstraction::new(project, control_flow_graph, pointer_inference, config);
string_abstraction.compute();
string_abstraction
}
#[cfg(test)]
pub mod tests;