diff --git a/src/relational/analysis.rs b/src/relational/analysis.rs index 52a2ec8..fbcf210 100644 --- a/src/relational/analysis.rs +++ b/src/relational/analysis.rs @@ -158,6 +158,13 @@ pub struct AccPath { pub projections: Vec, } +impl AccPath { + #[inline] + pub fn new(root: Local, projections: Vec) -> Self { + Self { root, projections } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum AccProj { Int(usize), diff --git a/src/relational/domains.rs b/src/relational/domains.rs index 96baec0..0f7171d 100644 --- a/src/relational/domains.rs +++ b/src/relational/domains.rs @@ -5,82 +5,15 @@ use rustc_middle::mir::Local; use super::*; #[derive(Debug, Clone)] -pub struct AbsMem { - pub non_rel: AbsNonRelMem, - pub rel: AbsRelMem, -} - -impl AbsMem { - #[inline] - pub fn bot() -> Self { - Self { - non_rel: AbsNonRelMem::bot(), - rel: AbsRelMem::bot(), - } - } - - #[inline] - pub fn join(&self, other: &Self) -> Self { - Self { - non_rel: self.non_rel.join(&other.non_rel), - rel: self.rel.join(&other.rel), - } - } - - #[inline] - pub fn ord(&self, other: &Self) -> bool { - self.non_rel.ord(&other.non_rel) && self.rel.ord(&other.rel) - } -} - -#[derive(Debug, Clone)] -pub struct AbsNonRelMem { - pub values: HashMap, -} - -impl AbsNonRelMem { - #[inline] - pub fn bot() -> Self { - Self { - values: HashMap::new(), - } - } - - pub fn join(&self, other: &Self) -> Self { - let keys: HashSet<_> = self.values.keys().chain(other.values.keys()).collect(); - let values = keys - .into_iter() - .map(|k| { - let bot = AbsValue::bot(); - let v1 = self.values.get(k).unwrap_or(&bot); - let v2 = other.values.get(k).unwrap_or(&bot); - (*k, v1.join(*v2)) - }) - .collect(); - Self { values } - } - - pub fn ord(&self, other: &Self) -> bool { - self.values.iter().all(|(k, v1)| { - let bot = AbsValue::bot(); - let v2 = other.values.get(k).unwrap_or(&bot); - v1.ord(v2) - }) - } -} - -#[derive(Debug, Clone, Copy)] -pub enum AbsValue { - Top, - Signed(i128), - Unsigned(u128), +pub enum AbsMem { Bot, + Mem(Graph), } -impl AbsValue { +impl AbsMem { #[inline] pub fn top() -> Self { - Self::Top + Self::Mem(Graph::default()) } #[inline] @@ -88,40 +21,12 @@ impl AbsValue { Self::Bot } - pub fn join(self, other: Self) -> Self { - match (self, other) { - (x, Self::Bot) | (Self::Bot, x) => x, - (Self::Signed(x), Self::Signed(y)) if x == y => self, - (Self::Unsigned(x), Self::Unsigned(y)) if x == y => self, - _ => Self::Top, - } - } - - pub fn ord(&self, other: &Self) -> bool { - match (self, other) { - (Self::Bot, _) | (_, Self::Top) => true, - (Self::Signed(x), Self::Signed(y)) if x == y => true, - (Self::Unsigned(x), Self::Unsigned(y)) if x == y => true, - _ => false, - } - } -} - -#[derive(Debug, Clone)] -pub enum AbsRelMem { - Bot, - Mem(Graph), -} - -impl AbsRelMem { - #[inline] - pub fn top() -> Self { - Self::Mem(Graph::default()) - } - #[inline] - pub fn bot() -> Self { - Self::Bot + pub fn graph_mut(&mut self) -> &mut Graph { + match self { + Self::Bot => panic!(), + Self::Mem(g) => g, + } } pub fn join(&self, other: &Self) -> Self { @@ -153,6 +58,15 @@ pub enum Int { Unsigned(u128), } +impl Int { + pub fn as_usize(self) -> usize { + match self { + Self::Signed(x) => x as usize, + Self::Unsigned(x) => x as usize, + } + } +} + #[derive(Debug, Clone)] pub enum Obj { Ptr(Location), @@ -221,7 +135,7 @@ impl Graph { (id, &mut self.nodes[id]) } - fn x_eq_y(&mut self, x: &AccPath, y: &AccPath) { + pub fn x_eq_y(&mut self, x: &AccPath, y: &AccPath) { let (id, _) = self.get_local_node(y.root); let loc = self.get_pointed_loc(id, &y.projections); @@ -229,7 +143,7 @@ impl Graph { *obj = Obj::Ptr(loc); } - fn x_eq_deref_y(&mut self, x: &AccPath, y: &AccPath) { + pub fn x_eq_deref_y(&mut self, x: &AccPath, y: &AccPath) { let (id, _) = self.get_local_node(y.root); let mut loc = self.get_pointed_loc(id, &[]); loc.projections.extend(y.projections.to_owned()); @@ -239,7 +153,7 @@ impl Graph { *obj = Obj::Ptr(loc); } - fn deref_x_eq_y(&mut self, x: &AccPath, y: &AccPath) { + pub fn deref_x_eq_y(&mut self, x: &AccPath, y: &AccPath) { let (id, _) = self.get_local_node(y.root); let loc_y = self.get_pointed_loc(id, &y.projections); @@ -252,7 +166,7 @@ impl Graph { *obj = Obj::Ptr(loc_y); } - fn x_eq_ref_y(&mut self, x: &AccPath, y: &AccPath) { + pub fn x_eq_ref_y(&mut self, x: &AccPath, y: &AccPath) { let (id, _) = self.get_local_node(y.root); let loc = Location::new(id, y.projections.to_owned()); @@ -260,13 +174,13 @@ impl Graph { *obj = Obj::Ptr(loc); } - fn x_eq_int(&mut self, x: &AccPath, n: Int) { + pub fn x_eq_int(&mut self, x: &AccPath, n: Int) { let id = self.get_int_node(n); let obj = self.get_obj(x); *obj = Obj::Ptr(Location::new(id, vec![])); } - fn deref_x_eq_int(&mut self, x: &AccPath, n: Int) { + pub fn deref_x_eq_int(&mut self, x: &AccPath, n: Int) { let n_id = self.get_int_node(n); let (id, _) = self.get_local_node(x.root); let mut loc = self.get_pointed_loc(id, &[]); @@ -275,7 +189,20 @@ impl Graph { *obj = Obj::Ptr(Location::new(n_id, vec![])); } - fn get_value(&mut self, x: &AccPath) -> Option { + pub fn x_eq(&mut self, x: &AccPath) { + let obj = self.get_obj(x); + *obj = Obj::new(); + } + + pub fn deref_x_eq(&mut self, x: &AccPath) { + let (id, _) = self.get_local_node(x.root); + let mut loc = self.get_pointed_loc(id, &[]); + loc.projections.extend(x.projections.to_owned()); + let obj = self.get_obj(x); + *obj = Obj::new(); + } + + pub fn get_int_value(&mut self, x: &AccPath) -> Option { let (id, _) = self.get_local_node(x.root); let loc = self.get_pointed_loc(id, &x.projections); if loc.projections.is_empty() { diff --git a/src/relational/semantics.rs b/src/relational/semantics.rs index c08bf7e..6bbe00c 100644 --- a/src/relational/semantics.rs +++ b/src/relational/semantics.rs @@ -1,10 +1,10 @@ use rustc_middle::{ mir::{ - interpret::{ConstValue, GlobalAlloc, Scalar}, - CastKind, ConstantKind, Location, Operand, ProjectionElem, Rvalue, Statement, - StatementKind, Terminator, + interpret::{ConstValue, Scalar}, + CastKind, ConstantKind, Location, Operand, Place, PlaceElem, ProjectionElem, Rvalue, + Statement, StatementKind, Terminator, }, - ty::TyKind, + ty::{IntTy, TyKind, UintTy}, }; use super::*; @@ -13,18 +13,33 @@ use crate::*; impl<'tcx> Analyzer<'tcx> { pub fn transfer_stmt(&self, stmt: &Statement<'tcx>, state: &mut AbsMem) { let StatementKind::Assign(box (l, r)) = &stmt.kind else { return }; - l.projection.iter().filter(|proj| match proj { - ProjectionElem::Deref => todo!(), - ProjectionElem::Field(_, _) => todo!(), - ProjectionElem::Index(_) => todo!(), - ProjectionElem::ConstantIndex { .. } => todo!(), - ProjectionElem::Subslice { .. } => todo!(), - ProjectionElem::Downcast(_, _) => todo!(), - ProjectionElem::OpaqueCast(_) => todo!(), - }); + let (l, l_deref) = AccPath::from_place(*l, state); match r { Rvalue::Use(r) => { - todo!() + let r = self.transfer_op(r, state); + let graph = state.graph_mut(); + match r { + OpVal::Place(r, r_deref) => match (l_deref, r_deref) { + (true, true) => panic!(), + (true, false) => graph.deref_x_eq_y(&l, &r), + (false, true) => graph.x_eq_deref_y(&l, &r), + (false, false) => graph.x_eq_y(&l, &r), + }, + OpVal::Int(n) => { + if l_deref { + graph.deref_x_eq_int(&l, n); + } else { + graph.x_eq_int(&l, n); + } + } + OpVal::Other => { + if l_deref { + graph.deref_x_eq(&l); + } else { + graph.x_eq(&l); + } + } + } } Rvalue::Cast(kind, r, _) => match kind { CastKind::PointerExposeAddress => todo!(), @@ -72,38 +87,45 @@ impl<'tcx> Analyzer<'tcx> { } } - fn transfer_operand(&self, l_id: usize, l_deref: bool, r: &Operand<'_>, state: &mut AbsRelMem) { - match r { - Operand::Copy(r) | Operand::Move(r) => { - let r_deref = r.is_indirect_first_projection(); - let r_id = r.local.as_usize(); - // match (l_deref, r_deref) { - // (false, false) => self.x_eq_y(l_id, r_id), - // (false, true) => self.x_eq_deref_y(l_id, r_id), - // (true, false) => self.deref_x_eq_y(l_id, r_id), - // (true, true) => self.deref_x_eq_deref_y(l_id, r_id), - // } + fn transfer_op(&self, op: &Operand<'_>, state: &mut AbsMem) -> OpVal { + match op { + Operand::Copy(place) | Operand::Move(place) => { + let (path, is_deref) = AccPath::from_place(*place, state); + OpVal::Place(path, is_deref) } Operand::Constant(box constant) => match constant.literal { ConstantKind::Ty(_) => unreachable!(), - ConstantKind::Unevaluated(_, _) => {} + ConstantKind::Unevaluated(_, _) => OpVal::Other, ConstantKind::Val(value, ty) => match value { ConstValue::Scalar(scalar) => match scalar { - Scalar::Int(_) => {} - Scalar::Ptr(ptr, _) => match self.tcx.global_alloc(ptr.provenance) { - GlobalAlloc::Static(def_id) => { - todo!() + Scalar::Int(i) => match ty.kind() { + TyKind::Int(int_ty) => { + let v = match int_ty { + IntTy::Isize => i.try_to_i64().unwrap() as _, + IntTy::I8 => i.try_to_i8().unwrap() as _, + IntTy::I16 => i.try_to_i16().unwrap() as _, + IntTy::I32 => i.try_to_i32().unwrap() as _, + IntTy::I64 => i.try_to_i64().unwrap() as _, + IntTy::I128 => i.try_to_i128().unwrap(), + }; + OpVal::Int(Int::Signed(v)) } - GlobalAlloc::Memory(_) => { - todo!() + TyKind::Uint(uint_ty) => { + let v = match uint_ty { + UintTy::Usize => i.try_to_u64().unwrap() as _, + UintTy::U8 => i.try_to_u8().unwrap() as _, + UintTy::U16 => i.try_to_u16().unwrap() as _, + UintTy::U32 => i.try_to_u32().unwrap() as _, + UintTy::U64 => i.try_to_u64().unwrap() as _, + UintTy::U128 => i.try_to_u128().unwrap(), + }; + OpVal::Int(Int::Unsigned(v)) } - _ => unreachable!(), + _ => OpVal::Other, }, + Scalar::Ptr(_, _) => OpVal::Other, }, - ConstValue::ZeroSized => { - let TyKind::FnDef(def_id, _) = ty.kind() else { unreachable!() }; - todo!() - } + ConstValue::ZeroSized => OpVal::Other, ConstValue::Slice { .. } => unreachable!(), ConstValue::ByRef { .. } => unreachable!(), }, @@ -114,8 +136,45 @@ impl<'tcx> Analyzer<'tcx> { pub fn transfer_term(&self, term: &Terminator<'tcx>) -> Vec<(Location, AbsMem)> { todo!() } +} - fn x_eq_y(&self, x: usize, y: usize, state: &mut AbsRelMem) {} +enum OpVal { + Place(AccPath, bool), + Int(Int), + Other, +} + +impl AccPath { + fn from_place(place: Place<'_>, state: &mut AbsMem) -> (Self, bool) { + let root = place.local; + let projections = place + .projection + .iter() + .filter_map(|e| AccProj::from_elem(e, state)) + .collect(); + let is_deref = place.is_indirect_first_projection(); + (AccPath::new(root, projections), is_deref) + } +} - fn deref_x_eq_y(&self, x: usize, y: usize, state: &mut AbsRelMem) {} +impl AccProj { + fn from_elem(proj: PlaceElem<'_>, state: &mut AbsMem) -> Option { + match proj { + ProjectionElem::Deref => None, + ProjectionElem::Field(i, _) => Some(AccProj::Int(i.index())), + ProjectionElem::Index(local) => { + let path = AccPath::new(local, vec![]); + if let Some(i) = state.graph_mut().get_int_value(&path) { + Some(AccProj::Int(i.as_usize())) + } else { + // TODO: aliasing + Some(AccProj::Symbolic([local].into_iter().collect())) + } + } + ProjectionElem::ConstantIndex { .. } => unreachable!(), + ProjectionElem::Subslice { .. } => unreachable!(), + ProjectionElem::Downcast(_, _) => unreachable!(), + ProjectionElem::OpaqueCast(_) => unreachable!(), + } + } }