Skip to content

Commit

Permalink
Merge pull request Artisan-Lab#70 from DiuDiu777/senryx
Browse files Browse the repository at this point in the history
Update call handling and test cases in Senryx
  • Loading branch information
hxuhack authored Nov 9, 2024
2 parents 2599c6a + 633cfb2 commit be93daa
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 47 deletions.
1 change: 1 addition & 0 deletions rap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ name = "cargo-rap"
name = "rap"

[dependencies]
lazy_static = "1.4"
snafu = "0.7.0"
chrono = "0.4.19"
serde_json = "1.0.72"
Expand Down
7 changes: 4 additions & 3 deletions rap/src/analysis/senryx.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod contracts;
pub mod inter_record;
pub mod matcher;
pub mod visitor;

Expand All @@ -21,7 +22,7 @@ impl<'tcx> SenryxCheck<'tcx> {
}

pub fn start(&self) {
let related_items = RelatedFnCollector::collect(self.tcx);
let related_items = RelatedFnCollector::collect(self.tcx); // find all func
let hir_map = self.tcx.hir();
for (_, &ref vec) in &related_items {
for (body_id, _span) in vec {
Expand Down Expand Up @@ -57,11 +58,11 @@ impl<'tcx> SenryxCheck<'tcx> {
pub fn pre_handle_type(&self, def_id: DefId) {
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);
let mut body_visitor = BodyVisitor::new(self.tcx, def_id, true);
if func_type == 1 {
let func_cons = uig_checker.search_constructor(def_id);
for func_con in func_cons {
let mut cons_body_visitor = BodyVisitor::new(self.tcx, func_con);
let mut cons_body_visitor = BodyVisitor::new(self.tcx, func_con, true);
cons_body_visitor.path_forward_check();
// TODO: cache fields' states

Expand Down
1 change: 1 addition & 0 deletions rap/src/analysis/senryx/contracts/abstract_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl AbstractStateItem {
}
}

#[derive(PartialEq)]
pub struct AbstractState {
pub state_map: HashMap<usize, AbstractStateItem>,
}
Expand Down
32 changes: 32 additions & 0 deletions rap/src/analysis/senryx/inter_record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use lazy_static::lazy_static;
use rustc_hir::def_id::DefId;
use std::{collections::HashMap, sync::Mutex};

use super::contracts::abstract_state::AbstractStateItem;

lazy_static! {
pub static ref GLOBAL_INTER_RECORDER: Mutex<HashMap<DefId, InterAnalysisRecord>> =
Mutex::new(HashMap::new());
}
// static mut GLOBAL_INTER_RECORDER: HashMap<DefId,InterAnalysisRecord> = HashMap::new();

pub struct InterAnalysisRecord {
pub pre_analysis_state: HashMap<usize, AbstractStateItem>,
pub post_analysis_state: HashMap<usize, AbstractStateItem>,
}

impl InterAnalysisRecord {
pub fn new(
pre_analysis_state: HashMap<usize, AbstractStateItem>,
post_analysis_state: HashMap<usize, AbstractStateItem>,
) -> Self {
Self {
pre_analysis_state,
post_analysis_state,
}
}

pub fn is_pre_state_same(&self, other_pre_state: &HashMap<usize, AbstractStateItem>) -> bool {
self.pre_analysis_state == *other_pre_state
}
}
66 changes: 40 additions & 26 deletions rap/src/analysis/senryx/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::{HashMap, HashSet};
use super::contracts::abstract_state::{
AbstractState, AbstractStateItem, AlignState, StateType, VType, Value,
};
use super::inter_record::{InterAnalysisRecord, GLOBAL_INTER_RECORDER};
use super::matcher::match_unsafe_api_and_check_contracts;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
Expand All @@ -23,17 +24,19 @@ pub struct BodyVisitor<'tcx> {
// abstract_states records the path index and variables' ab states in this path
pub abstract_states: HashMap<usize, AbstractState>,
pub unsafe_callee_report: HashMap<String, usize>,
pub first_layer_flag: bool,
}

impl<'tcx> BodyVisitor<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, def_id: DefId) -> Self {
pub fn new(tcx: TyCtxt<'tcx>, def_id: DefId, first_layer_flag: bool) -> Self {
let body = tcx.optimized_mir(def_id);
Self {
tcx,
def_id,
safedrop_graph: SafeDropGraph::new(body, tcx, def_id),
abstract_states: HashMap::new(),
unsafe_callee_report: HashMap::new(),
first_layer_flag,
}
}

Expand Down Expand Up @@ -97,23 +100,25 @@ impl<'tcx> BodyVisitor<'tcx> {
} => {
let func_name = format!("{:?}", func);
if let Operand::Constant(func_constant) = func {
if let ty::FnDef(ref _callee_def_id, raw_list) =
func_constant.const_.ty().kind()
if let ty::FnDef(ref callee_def_id, raw_list) = func_constant.const_.ty().kind()
{
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 self.first_layer_flag {
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,
);
}
_ => {}
}
_ => {}
}
}
//TODO:path_inter_analyze
self.handle_call(callee_def_id);
}
}
}
Expand Down Expand Up @@ -185,19 +190,6 @@ impl<'tcx> BodyVisitor<'tcx> {
);
self.insert_path_abstate(path_index, lpjc_local, abitem);
}
// Rvalue::AddressOf(_, rplace) => {
// let align = 0;
// let size = 0;
// let abitem = AbstractStateItem::new(
// (Value::None, Value::None),
// VType::Pointer(align, size),
// HashSet::from([StateType::AlignState(AlignState::Aligned)]),
// );
// self.insert_path_abstate(path_index, lpjc_local, abitem);
// let _rpjc_local = self
// .safedrop_graph
// .projection(self.tcx, true, rplace.clone());
// }
Rvalue::Cast(_cast_kind, op, ty) => match op {
Operand::Move(rplace) | Operand::Copy(rplace) => {
let rpjc_local = self
Expand Down Expand Up @@ -243,6 +235,26 @@ impl<'tcx> BodyVisitor<'tcx> {
}
}

pub fn handle_call(&mut self, def_id: &DefId) {
let pre_analysis_state = HashMap::new();
let mut recorder = GLOBAL_INTER_RECORDER.lock().unwrap();
if let Some(record) = recorder.get_mut(def_id) {
if record.is_pre_state_same(&pre_analysis_state) {
// update directly
self.update_inter_state_directly();
return;
}
}
let _inter_body_visitor = BodyVisitor::new(self.tcx, *def_id, false).path_forward_check();
let post_analysis_state = HashMap::new();
recorder.insert(
*def_id,
InterAnalysisRecord::new(pre_analysis_state, post_analysis_state),
);
}

pub fn update_inter_state_directly(&mut self) {}

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) => {
Expand Down Expand Up @@ -364,4 +376,6 @@ impl<'tcx> BodyVisitor<'tcx> {
let size = layout.size.bytes() as usize;
(align, size)
}

pub fn get_abstate_by_place(&self) {}
}
95 changes: 77 additions & 18 deletions tests/senryx_tests/slice_from_raw_parts/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,79 @@
use std::ptr;
use std::slice;
use std::mem::MaybeUninit;

// fn test1() {
// let data: *const u8 = Box::leak(Box::new(0));
// let len: usize = (isize::MAX as usize) / std::mem::size_of::<u8>() + 1;
// // Pass(Allocated \ Aligned): data is allocated and aligned
// // Fail(Bounded): 'len' is out of the max value
// // Fail(Dereferencable \ Initialized): 'data' onnly points to the memory with a 'u8' size, but the 'len' is out of this range
// let slice: &[u8] = unsafe { slice::from_raw_parts(data, len) };
// if let Some(last_element) = slice.last() {
// println!("Last element: {}", last_element);
// } else {
// println!("Slice is empty");
// }
// }

fn test2(a: &mut [u8], b: &[u32; 20]) {
struct MySliceWrapperTest<T> {
data: *const T,
len: usize,
}

impl<T> MySliceWrapperTest<T> {
fn new() -> Self {
let uninit_data = MaybeUninit::<[T; 10]>::uninit();
let data = uninit_data.as_ptr() as *const T;
MySliceWrapperTest { data, len: 10 }
}

fn get_slice(&self, offset: usize, length: usize) -> &[T] {
assert!(offset + length <= self.len, "Requested slice is out of bounds");
let adjusted_data = unsafe { self.data.add(offset) };
// Fail(Allocated): 'adjusted_data' points to uninit memory
// Fail(Aligned): 'adjusted_data' may be not aligned due to the offset
unsafe { slice::from_raw_parts(adjusted_data, length) }
}
}


fn test1() {
let len: usize = 0;
let data = ptr::null::<i32>();
// Fail(Allocated): 'data' is null, which violates the requirement that it must be non-null
let slice: &[i32] = unsafe { slice::from_raw_parts(data, len) };
}

fn test2() {
let len: usize = 3;
let uninit_data = MaybeUninit::<[i32; 3]>::uninit();
let data = uninit_data.as_ptr() as *const i32;
// Fail(Initialized): 'data' points to uninitialized memory, which violates the initialization requirement
let slice: &[i32] = unsafe { slice::from_raw_parts(data, len) };
println!("First element: {}", slice[0]);
}

fn test3() {
let part1 = Box::new(1);
let part2 = Box::new(2);
let data = [Box::into_raw(part1), Box::into_raw(part2)].as_ptr() as *const i32;
let len = 2;
// Fail(Dereferencable): 'data' points across multiple allocated objects, violating the single allocation constraint
let slice: &[i32] = unsafe { slice::from_raw_parts(data, len) };
println!("Slice elements: {:?}", slice);
}

fn test4() {
let unaligned = [0u8; 5];
let data = unaligned.as_ptr().wrapping_offset(1) as *const i32;
let len = 1;
// Fail(Layout): 'data' is not aligned, violating the alignment requirement
let slice: &[i32] = unsafe { slice::from_raw_parts(data, len) };
println!("Slice elements: {:?}", slice);
}

fn test5() {
let data: *const u8 = Box::leak(Box::new(0));
let len: usize = (isize::MAX as usize) / std::mem::size_of::<u8>() + 1;
// Pass(Allocated \ Aligned): data is allocated and aligned
// Fail(Bounded): 'len' is out of the max value
// Fail(Dereferencable \ Initialized): 'data' onnly points to the memory with a 'u8' size, but the 'len' is out of this range
let slice: &[u8] = unsafe { slice::from_raw_parts(data, len) };
if let Some(last_element) = slice.last() {
println!("Last element: {}", last_element);
} else {
println!("Slice is empty");
}
}

fn test6(a: &mut [u8], b: &[u32; 20]) {
unsafe {
let c = slice::from_raw_parts_mut(a.as_mut_ptr() as *mut u32, 20);
for i in 0..20 {
Expand All @@ -24,8 +83,8 @@ fn test2(a: &mut [u8], b: &[u32; 20]) {
}

fn main() {
// test1();
test1();
let mut x = [0u8;40];
let y = [0u32;20];
test2(&mut x[1..32], &y);
}
// test2(&mut x[1..32], &y);
}

0 comments on commit be93daa

Please sign in to comment.