From 3a331daee011fb3d580616e435af804f8d3674cd Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Tue, 26 Nov 2024 17:03:22 +0800 Subject: [PATCH 1/4] set util function display_mir public --- rap/src/analysis/utils/show_mir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rap/src/analysis/utils/show_mir.rs b/rap/src/analysis/utils/show_mir.rs index 9c0442a..cf68300 100644 --- a/rap/src/analysis/utils/show_mir.rs +++ b/rap/src/analysis/utils/show_mir.rs @@ -191,8 +191,8 @@ pub struct ShowMir<'tcx> { pub tcx: TyCtxt<'tcx>, } -#[inline(always)] -fn display_mir(did: DefId, body: &Body) { +// #[inline(always)] +pub fn display_mir(did: DefId, body: &Body) { rap_info!("{}", did.display().color(Color::LightRed)); rap_info!("{}", body.local_decls.display().color(Color::Green)); rap_info!( From 76b73b56374753c1c76dadd3f4471887417619af Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Tue, 26 Nov 2024 20:44:26 +0800 Subject: [PATCH 2/4] beautify check results output --- rap/src/analysis/senryx.rs | 38 ++++--- rap/src/analysis/senryx/matcher.rs | 29 ++++-- rap/src/analysis/senryx/visitor.rs | 160 +++++++++++++++++++++-------- 3 files changed, 165 insertions(+), 62 deletions(-) diff --git a/rap/src/analysis/senryx.rs b/rap/src/analysis/senryx.rs index e6c9470..b42c308 100644 --- a/rap/src/analysis/senryx.rs +++ b/rap/src/analysis/senryx.rs @@ -9,7 +9,7 @@ use crate::analysis::unsafety_isolation::{ }; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; -use visitor::BodyVisitor; +use visitor::{BodyVisitor, CheckResult}; pub struct SenryxCheck<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -40,22 +40,20 @@ impl<'tcx> SenryxCheck<'tcx> { } pub fn check_soundness(&self, def_id: DefId) { - self.pre_handle_type(def_id); - println!( - "Find unsound safe api, def_id: {:?}, location: {:?}, ", - def_id, def_id - ); + let check_results = self.body_visit_and_check(def_id); + if check_results.len() > 0 { + Self::show_check_results(def_id, check_results); + } } pub fn annotate_safety(&self, def_id: DefId) { - self.pre_handle_type(def_id); - println!( - "Annotate unsafe api, def_id: {:?}, location: {:?}, ", - def_id, def_id - ); + let check_results = self.body_visit_and_check(def_id); + if check_results.len() > 0 { + Self::show_check_results(def_id, check_results); + } } - pub fn pre_handle_type(&self, def_id: DefId) { + pub fn body_visit_and_check(&self, def_id: DefId) -> Vec { let mut uig_checker = UnsafetyIsolationCheck::new(self.tcx); let func_type = uig_checker.get_type(def_id); let mut body_visitor = BodyVisitor::new(self.tcx, def_id, 0); @@ -74,5 +72,21 @@ impl<'tcx> SenryxCheck<'tcx> { } else { body_visitor.path_forward_check(); } + return body_visitor.check_results; + } + + pub fn show_check_results(def_id: DefId, check_results: Vec) { + println!("--------In {:?}---------", def_id); + for check_result in check_results { + println!( + " Unsafe api {:?}: {} passed, {} failed!", + check_result.func_name, + check_result.passed_contracts.len(), + check_result.failed_contracts.len() + ); + for failed_contract in check_result.failed_contracts { + println!(" Contract failed: {:?}", failed_contract); + } + } } } diff --git a/rap/src/analysis/senryx/matcher.rs b/rap/src/analysis/senryx/matcher.rs index 991dfdf..8bdfd15 100644 --- a/rap/src/analysis/senryx/matcher.rs +++ b/rap/src/analysis/senryx/matcher.rs @@ -1,10 +1,13 @@ use rustc_middle::mir::Operand; use rustc_span::source_map::Spanned; -use super::contracts::{ - abstract_state::AbstractState, - checker::{Checker, SliceFromRawPartsChecker}, - contract::check_contract, +use super::{ + contracts::{ + abstract_state::AbstractState, + checker::{Checker, SliceFromRawPartsChecker}, + contract::check_contract, + }, + visitor::CheckResult, }; pub fn match_unsafe_api_and_check_contracts( @@ -12,7 +15,7 @@ pub fn match_unsafe_api_and_check_contracts( args: &Box<[Spanned]>, abstate: &AbstractState, _ty: T, -) { +) -> Option { let base_func_name = func_name.split::<&str>("<").next().unwrap_or(func_name); // println!("base name ---- {:?}",base_func_name); let checker: Option> = match base_func_name { @@ -23,11 +26,18 @@ pub fn match_unsafe_api_and_check_contracts( }; if let Some(c) = checker { - process_checker(&*c, args, abstate); + return Some(process_checker(&*c, args, abstate, base_func_name)); } + None } -fn process_checker(checker: &dyn Checker, args: &Box<[Spanned]>, abstate: &AbstractState) { +fn process_checker( + checker: &dyn Checker, + args: &Box<[Spanned]>, + abstate: &AbstractState, + func_name: &str, +) -> CheckResult { + let mut check_result = CheckResult::new(func_name); for (idx, contracts_vec) in checker.variable_contracts().iter() { for contract in contracts_vec { let arg_place = get_arg_place(&args[*idx].node); @@ -36,13 +46,14 @@ fn process_checker(checker: &dyn Checker, args: &Box<[Spanned]>, abstat } if let Some(abstate_item) = abstate.state_map.get(&arg_place) { if !check_contract(*contract, &abstate_item.clone().unwrap()) { - println!("Contract failed! ---- {:?}", contract); + check_result.failed_contracts.push((*idx, *contract)); } else { - println!("Contract passed! ---- {:?}", contract); + check_result.passed_contracts.push((*idx, *contract)); } } } } + check_result } pub fn get_arg_place(arg: &Operand) -> usize { diff --git a/rap/src/analysis/senryx/visitor.rs b/rap/src/analysis/senryx/visitor.rs index 64c8bf9..3d6a526 100644 --- a/rap/src/analysis/senryx/visitor.rs +++ b/rap/src/analysis/senryx/visitor.rs @@ -1,24 +1,43 @@ use crate::analysis::safedrop::graph::SafeDropGraph; -// use crate::analysis::utils::show_mir::display_mir; +use crate::analysis::utils::show_mir::display_mir; use crate::rap_warn; use rustc_span::source_map::Spanned; use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; +use std::hash::Hash; use super::contracts::abstract_state::{ AbstractState, AbstractStateItem, AlignState, StateType, VType, Value, }; +use super::contracts::contract::Contract; use super::inter_record::{InterAnalysisRecord, GLOBAL_INTER_RECORDER}; use super::matcher::{get_arg_place, match_unsafe_api_and_check_contracts}; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; use rustc_middle::{ mir::{ - self, AggregateKind, BasicBlock, BasicBlockData, CastKind, Local, Operand, Place, Rvalue, + self, AggregateKind, BasicBlock, BasicBlockData, BinOp, CastKind, Operand, Place, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }, ty::{self, GenericArgKind, Ty, TyKind}, }; +pub struct CheckResult { + pub func_name: String, + pub failed_contracts: Vec<(usize, Contract)>, + pub passed_contracts: Vec<(usize, Contract)>, +} + +impl CheckResult { + pub fn new(func_name: &str) -> Self { + Self { + func_name: func_name.to_string(), + failed_contracts: Vec::new(), + passed_contracts: Vec::new(), + } + } +} + pub struct BodyVisitor<'tcx> { pub tcx: TyCtxt<'tcx>, pub def_id: DefId, @@ -26,7 +45,9 @@ pub struct BodyVisitor<'tcx> { // abstract_states records the path index and variables' ab states in this path pub abstract_states: HashMap, pub unsafe_callee_report: HashMap, + pub local_ty: HashMap, pub visit_time: usize, + pub check_results: Vec, } impl<'tcx> BodyVisitor<'tcx> { @@ -38,13 +59,21 @@ impl<'tcx> BodyVisitor<'tcx> { safedrop_graph: SafeDropGraph::new(body, tcx, def_id), abstract_states: HashMap::new(), unsafe_callee_report: HashMap::new(), + local_ty: HashMap::new(), visit_time, + check_results: Vec::new(), } } pub fn path_forward_check(&mut self) { let paths = self.get_all_paths(); let body = self.tcx.optimized_mir(self.def_id); + let locals = body.local_decls.clone(); + for (idx, local) in locals.iter().enumerate() { + let local_ty = local.ty; + let layout = self.visit_ty_and_get_layout(local_ty); + self.local_ty.insert(idx, layout); + } // display_mir(self.def_id,&body); for (index, path_info) in paths.iter().enumerate() { self.abstract_states.insert(index, AbstractState::new()); @@ -60,7 +89,6 @@ impl<'tcx> BodyVisitor<'tcx> { let tem_scc_sub_blocks = self.safedrop_graph.blocks[*block_index] .scc_sub_blocks .clone(); - // println!("father block {:?} scc sub blocks {:?}", block_index, tem_scc_sub_blocks); if tem_scc_sub_blocks.len() > 0 { for sub_block in &tem_scc_sub_blocks { self.path_analyze_block( @@ -73,12 +101,7 @@ impl<'tcx> BodyVisitor<'tcx> { } } // self.abstract_states_mop(); - if self.visit_time == 0 { - // display_mir(self.def_id,body); - println!("---------------"); - println!("--def_id: {:?} \n--paths: {:?}", self.def_id, paths); - self.abstate_debug(); - } + // self.abstate_debug(); } pub fn path_analyze_block( @@ -115,12 +138,16 @@ impl<'tcx> BodyVisitor<'tcx> { for generic_arg in raw_list.iter() { match generic_arg.unpack() { GenericArgKind::Type(ty) => { - match_unsafe_api_and_check_contracts( - func_name.as_str(), - args, - &self.abstract_states.get(&path_index).unwrap(), - ty, - ); + if let Some(check_result) = + match_unsafe_api_and_check_contracts( + func_name.as_str(), + args, + &self.abstract_states.get(&path_index).unwrap(), + ty, + ) + { + self.check_results.push(check_result); + } } _ => {} } @@ -176,9 +203,7 @@ impl<'tcx> BodyVisitor<'tcx> { .safedrop_graph .projection(self.tcx, true, rplace.clone()); if let Some(ab_state) = self.abstract_states.get(&path_index) { - // println!("------{:?}, {:?}-----",path_index,rpjc_local); if let Some(r_state_item) = ab_state.state_map.get(&rpjc_local) { - // println!("------{:?}-----",r_state_item.clone().unwrap()); self.insert_path_abstate(path_index, lpjc_local, r_state_item.clone()); } } @@ -227,9 +252,9 @@ impl<'tcx> BodyVisitor<'tcx> { AggregateKind::Array(_ty) => {} _ => {} }, - // Rvalue::Discriminant(_place) => { - // println!("{}:{:?}",llocal,rvalue); - // } + Rvalue::Discriminant(_place) => { + // println!("Discriminant {}:{:?}",lpjc_local,rvalue); + } _ => {} } } @@ -308,15 +333,6 @@ impl<'tcx> BodyVisitor<'tcx> { result_states } - pub fn visit_ty_and_get_layout(&self, ty: Ty<'tcx>) -> (usize, usize) { - match ty.kind() { - TyKind::RawPtr(ty, _) | TyKind::Ref(_, ty, _) | TyKind::Slice(ty) => { - self.get_layout_by_ty(*ty) - } - _ => (0, 0), - } - } - pub fn get_all_paths(&mut self) -> Vec> { self.safedrop_graph.solve_scc(); let results = self.safedrop_graph.get_paths(); @@ -346,9 +362,21 @@ impl<'tcx> BodyVisitor<'tcx> { } pub fn abstate_debug(&self) { - for (path, abstract_state) in &self.abstract_states { - println!("Path-{:?}:", path); - for (place, ab_item) in &abstract_state.state_map { + if self.visit_time != 0 { + return; + } + Self::display_hashmap(&self.local_ty, 1); + display_mir(self.def_id, self.tcx.optimized_mir(self.def_id)); + println!("---------------"); + println!("--def_id: {:?}", self.def_id); + + let mut sorted_states: Vec<_> = self.abstract_states.iter().collect(); + sorted_states.sort_by(|a, b| a.0.cmp(b.0)); + for (path, abstract_state) in &sorted_states { + println!("--Path-{:?}:", path); + let mut sorted_state_map: Vec<_> = abstract_state.state_map.iter().collect(); + sorted_state_map.sort_by_key(|&(place, _)| place); + for (place, ab_item) in sorted_state_map { println!("Place-{:?} has abstract states:{:?}", place, ab_item); } } @@ -410,9 +438,6 @@ impl<'tcx> BodyVisitor<'tcx> { place: usize, abitem: Option, ) { - if self.visit_time == 0 { - println!("insert state of place: {}", place); - } self.abstract_states .entry(path_index) .or_insert_with(|| AbstractState { @@ -423,10 +448,17 @@ impl<'tcx> BodyVisitor<'tcx> { } pub fn get_layout_by_place_usize(&self, place: usize) -> (usize, usize) { - let local_place = Place::from(Local::from_usize(place)); - let body = self.tcx.optimized_mir(self.def_id); - let place_ty = local_place.ty(body, self.tcx).ty; - self.visit_ty_and_get_layout(place_ty) + *self.local_ty.get(&place).unwrap() + } + + pub fn visit_ty_and_get_layout(&self, ty: Ty<'tcx>) -> (usize, usize) { + match ty.kind() { + TyKind::RawPtr(ty, _) + | TyKind::Ref(_, ty, _) + | TyKind::Slice(ty) + | TyKind::Array(ty, _) => self.get_layout_by_ty(*ty), + _ => (0, 0), + } } pub fn get_layout_by_ty(&self, ty: Ty<'tcx>) -> (usize, usize) { @@ -436,6 +468,13 @@ impl<'tcx> BodyVisitor<'tcx> { let align = layout.align.abi.bytes_usize(); let size = layout.size.bytes() as usize; return (align, size); + } else { + match ty.kind() { + TyKind::Array(inner_ty, _) | TyKind::Slice(inner_ty) => { + return self.get_layout_by_ty(*inner_ty); + } + _ => {} + } } return (0, 0); } @@ -453,6 +492,22 @@ impl<'tcx> BodyVisitor<'tcx> { return None; } + pub fn display_hashmap(map: &HashMap, level: usize) + where + K: Ord + Debug + Hash, + V: Debug, + { + let indent = " ".repeat(level); + let mut sorted_keys: Vec<_> = map.keys().collect(); + sorted_keys.sort(); + + for key in sorted_keys { + if let Some(value) = map.get(key) { + println!("{}{:?}: {:?}", indent, key, value); + } + } + } + pub fn handle_cast( &mut self, rpjc_local: usize, @@ -463,7 +518,7 @@ impl<'tcx> BodyVisitor<'tcx> { ) { let mut src_align = self.get_layout_by_place_usize(rpjc_local).0; match cast_kind { - CastKind::PtrToPtr => { + CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) => { if let Some(r_abitem) = self.get_abstate_by_place_in_path(rpjc_local, path_index) { for state in &r_abitem.state { if let StateType::AlignState(r_align_state) = state { @@ -498,5 +553,28 @@ impl<'tcx> BodyVisitor<'tcx> { } } - pub fn handle_binary_op(&mut self) {} + pub fn handle_binary_op( + &mut self, + first_op: &Operand, + bin_op: &BinOp, + second_op: &Operand, + path_index: usize, + ) { + match bin_op { + BinOp::Offset => { + let first_place = self.handle_operand(first_op); + let _second_place = self.handle_operand(second_op); + let _abitem = self.get_abstate_by_place_in_path(first_place, path_index); + } + _ => {} + } + } + + pub fn handle_operand(&self, op: &Operand) -> usize { + match op { + Operand::Move(place) => place.local.as_usize(), + Operand::Copy(place) => place.local.as_usize(), + _ => 0, + } + } } From c89921fb130efe38a8b191b347e716d0136c1f39 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Tue, 26 Nov 2024 21:23:35 +0800 Subject: [PATCH 3/4] fix: merge redundant output in different paths --- rap/src/analysis/senryx/matcher.rs | 7 +++++-- rap/src/analysis/senryx/visitor.rs | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/rap/src/analysis/senryx/matcher.rs b/rap/src/analysis/senryx/matcher.rs index 8bdfd15..4e08c41 100644 --- a/rap/src/analysis/senryx/matcher.rs +++ b/rap/src/analysis/senryx/matcher.rs @@ -1,5 +1,6 @@ use rustc_middle::mir::Operand; use rustc_span::source_map::Spanned; +use rustc_span::Span; use super::{ contracts::{ @@ -14,6 +15,7 @@ pub fn match_unsafe_api_and_check_contracts( func_name: &str, args: &Box<[Spanned]>, abstate: &AbstractState, + span: Span, _ty: T, ) -> Option { let base_func_name = func_name.split::<&str>("<").next().unwrap_or(func_name); @@ -26,7 +28,7 @@ pub fn match_unsafe_api_and_check_contracts( }; if let Some(c) = checker { - return Some(process_checker(&*c, args, abstate, base_func_name)); + return Some(process_checker(&*c, args, abstate, base_func_name, span)); } None } @@ -36,8 +38,9 @@ fn process_checker( args: &Box<[Spanned]>, abstate: &AbstractState, func_name: &str, + span: Span, ) -> CheckResult { - let mut check_result = CheckResult::new(func_name); + let mut check_result = CheckResult::new(func_name, span); for (idx, contracts_vec) in checker.variable_contracts().iter() { for contract in contracts_vec { let arg_place = get_arg_place(&args[*idx].node); diff --git a/rap/src/analysis/senryx/visitor.rs b/rap/src/analysis/senryx/visitor.rs index 3d6a526..c2c218b 100644 --- a/rap/src/analysis/senryx/visitor.rs +++ b/rap/src/analysis/senryx/visitor.rs @@ -2,6 +2,7 @@ use crate::analysis::safedrop::graph::SafeDropGraph; use crate::analysis::utils::show_mir::display_mir; use crate::rap_warn; use rustc_span::source_map::Spanned; +use rustc_span::Span; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::hash::Hash; @@ -22,16 +23,19 @@ use rustc_middle::{ ty::{self, GenericArgKind, Ty, TyKind}, }; +//TODO: modify contracts vec to contract-bool pairs (we can also use path index to record path info) pub struct CheckResult { pub func_name: String, + pub func_span: Span, pub failed_contracts: Vec<(usize, Contract)>, pub passed_contracts: Vec<(usize, Contract)>, } impl CheckResult { - pub fn new(func_name: &str) -> Self { + pub fn new(func_name: &str, func_span: Span) -> Self { Self { func_name: func_name.to_string(), + func_span, failed_contracts: Vec::new(), passed_contracts: Vec::new(), } @@ -128,7 +132,9 @@ impl<'tcx> BodyVisitor<'tcx> { args, destination: _, target: _, - .. + unwind: _, + call_source: _, + fn_span, } => { let func_name = format!("{:?}", func); if let Operand::Constant(func_constant) = func { @@ -138,15 +144,23 @@ impl<'tcx> BodyVisitor<'tcx> { for generic_arg in raw_list.iter() { match generic_arg.unpack() { GenericArgKind::Type(ty) => { - if let Some(check_result) = + if let Some(new_check_result) = match_unsafe_api_and_check_contracts( func_name.as_str(), args, &self.abstract_states.get(&path_index).unwrap(), + *fn_span, ty, ) { - self.check_results.push(check_result); + if let Some(_existing) = + self.check_results.iter_mut().find(|result| { + result.func_name == new_check_result.func_name + }) + { + } else { + self.check_results.push(new_check_result); + } } } _ => {} From 57c3a64bf89c1bad142f75c0c3d4c8f5ec888827 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Mon, 2 Dec 2024 11:19:27 +0800 Subject: [PATCH 4/4] updata checker --- rap/src/analysis/senryx/contracts/checker.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rap/src/analysis/senryx/contracts/checker.rs b/rap/src/analysis/senryx/contracts/checker.rs index e26ae21..ba935f8 100644 --- a/rap/src/analysis/senryx/contracts/checker.rs +++ b/rap/src/analysis/senryx/contracts/checker.rs @@ -25,10 +25,10 @@ impl SliceFromRawPartsChecker { map.insert( 0, vec![ - Contract::StateCheck { - op: Op::GE, - state: StateType::AllocatedState(AllocatedState::Alloc), - }, + // Contract::StateCheck { + // op: Op::GE, + // state: StateType::AllocatedState(AllocatedState::Alloc), + // }, Contract::StateCheck { op: Op::GT, state: StateType::AlignState(AlignState::Unaligned),