1use crate::analysis::{
8 core::alias_analysis::FnAliasPairs,
9 utils::fn_info::{
10 generate_contract_from_std_annotation_json, get_cleaned_def_path_name, get_sp_tags_json,
11 reflect_generic,
12 },
13};
14use crate::check::senryx::{contract::PropertyContract, visitor::BodyVisitor};
15use rustc_data_structures::fx::FxHashMap;
16use rustc_hir::def_id::DefId;
17use rustc_middle::{
18 mir::{Const, Operand, Place},
19 ty::Ty,
20};
21use rustc_span::{Span, source_map::Spanned};
22pub(crate) fn has_unsafe_api_contract(func_name: &str) -> bool {
24 get_sp_tags_json().get(func_name).is_some()
25}
26
27pub(crate) fn get_arg_place(arg: &Operand) -> (bool, usize) {
31 match arg {
32 Operand::Move(place) | Operand::Copy(place) => (false, place.local.as_usize()),
33 Operand::Constant(constant) => {
34 let mut val = 0;
35 match constant.const_ {
36 Const::Ty(_ty, _const_value) => {
37 rap_warn!("const ty found!");
38 }
39 Const::Unevaluated(_unevaluated, _ty) => {}
40 Const::Val(const_value, _ty) => {
41 if let Some(scalar) = const_value.try_to_scalar_int() {
42 val = scalar.to_uint(scalar.size()) as usize;
43 }
44 }
45 }
46 (true, val)
47 }
48 }
49}
50
51impl<'tcx> BodyVisitor<'tcx> {
52 pub fn handle_std_unsafe_call(
54 &mut self,
55 _dst_place: &Place<'_>,
56 def_id: &DefId,
57 args: &[Spanned<Operand>],
58 _path_index: usize,
59 _fn_map: &FxHashMap<DefId, FnAliasPairs>,
60 fn_span: Span,
61 generic_mapping: FxHashMap<String, Ty<'tcx>>,
62 ) {
63 let func_name = get_cleaned_def_path_name(self.tcx, *def_id);
64 let args_with_contracts = generate_contract_from_std_annotation_json(self.tcx, *def_id);
65
66 for (idx, (base, fields, contract)) in args_with_contracts.iter().enumerate() {
67 rap_debug!("Find contract for {:?}, {base}: {:?}", def_id, contract);
68 if *base >= args.len() {
69 continue;
70 }
71
72 let arg_tuple = get_arg_place(&args[*base].node);
73 if arg_tuple.0 {
74 continue;
75 }
76
77 let arg_place = self.chains.find_var_id_with_fields_seq(arg_tuple.1, fields);
78 self.check_contract(
79 arg_place,
80 args,
81 contract.clone(),
82 &generic_mapping,
83 func_name.clone(),
84 fn_span,
85 idx,
86 );
87 }
88 }
89
90 pub fn check_contract(
92 &mut self,
93 arg: usize,
94 _args: &[Spanned<Operand>],
95 contract: PropertyContract<'tcx>,
96 generic_mapping: &FxHashMap<String, Ty<'tcx>>,
97 func_name: String,
98 fn_span: Span,
99 idx: usize,
100 ) -> bool {
101 rap_debug!("Check contract {:?} for {:?}.", contract, func_name);
102 let (sp_name, check_result) = match contract {
103 PropertyContract::Align(ty) => {
104 let contract_required_ty = reflect_generic(generic_mapping, &func_name, ty);
105 ("Align", self.check_align(arg, contract_required_ty))
106 }
107 PropertyContract::InBound(ty, contract_len) => {
108 let contract_required_ty = reflect_generic(generic_mapping, &func_name, ty);
109 (
110 "Inbound",
111 self.check_inbound(arg, contract_len, contract_required_ty),
112 )
113 }
114 PropertyContract::NonNull => ("NonNull", self.check_non_null(arg)),
115 PropertyContract::Typed(_ty) => ("Typed", self.check_typed(arg)),
116 PropertyContract::ValidPtr(ty, contract_len) => {
117 let contract_required_ty = reflect_generic(generic_mapping, &func_name, ty);
118 (
119 "ValidPtr",
120 self.check_valid_ptr(arg, contract_len, contract_required_ty),
121 )
122 }
123 PropertyContract::ValidNum(predicates) => {
124 ("ValidNum", self.check_valid_num(&predicates))
125 }
126 _ => ("Unknown", false),
127 };
128
129 self.insert_checking_result(sp_name, check_result, func_name, fn_span, idx);
130 true
131 }
132}