rapx/analysis/senryx/contracts/
property.rs1use crate::{
2 analysis::utils::fn_info::{
3 access_ident_recursive, match_ty_with_ident, parse_expr_into_local_and_ty,
4 parse_expr_into_number,
5 },
6 rap_error,
7};
8use rustc_hir::def_id::DefId;
9use rustc_middle::mir::BinOp;
10use rustc_middle::ty::Ty;
11use rustc_middle::ty::TyCtxt;
12use safety_parser::{
13 property_attr::property::{Kind, PropertyName},
14 syn::Expr,
15};
16
17#[derive(Clone, Debug)]
18pub enum CisRangeItem {
19 Var(usize, Vec<usize>),
20 Value(usize),
21 Unknown,
22}
23
24impl CisRangeItem {
25 pub fn get_var_base(&self) -> Option<usize> {
26 match self {
27 Self::Var(base, _) => Some(*base),
28 _ => None,
29 }
30 }
31
32 pub fn new_var(base: usize) -> Self {
33 Self::Var(base, Vec::new())
34 }
35
36 pub fn new_value(value: usize) -> Self {
37 Self::Value(value)
38 }
39
40 pub fn new_unknown() -> Self {
41 Self::Unknown
42 }
43}
44
45#[derive(Clone, Debug)]
46pub struct CisRange {
47 pub bin_op: BinOp,
48 pub range: CisRangeItem,
49}
50
51impl CisRange {
52 pub fn new(bin_op: BinOp, range: CisRangeItem) -> Self {
53 Self { bin_op, range }
54 }
55}
56
57#[derive(Clone, Debug)]
58pub enum PropertyContract<'tcx> {
59 Align(Ty<'tcx>),
61 Size(Kind),
62 NoPadding,
63 NonNull,
64 Allocated(Ty<'tcx>, CisRangeItem),
66 InBound(Ty<'tcx>, CisRangeItem),
68 NonOverlap,
69 ValidNum(CisRange),
70 ValidString,
71 ValidCStr,
72 Init(Ty<'tcx>, CisRangeItem),
74 Unwrap,
75 Typed(Ty<'tcx>),
76 Owning,
77 Alias,
78 Alive,
79 Pinned,
80 NonVolatile,
81 Opened,
82 Trait,
83 Unreachable,
84 ValidPtr(Ty<'tcx>, CisRangeItem),
85 Deref,
86 Ptr2Ref,
87 Layout,
88 Unknown,
89}
90
91impl<'tcx> PropertyContract<'tcx> {
92 pub fn new(
93 tcx: TyCtxt<'tcx>,
94 def_id: DefId,
95 kind: Kind,
96 name: PropertyName,
97 exprs: &Vec<Expr>,
98 ) -> Self {
99 match name {
100 PropertyName::Align => {
101 Self::check_arg_length(exprs.len(), 2, "Align");
102 let ty = Self::parse_type(tcx, def_id, &exprs[1], "Align");
103 Self::Align(ty)
104 }
105 PropertyName::Size => Self::Size(kind),
106 PropertyName::NoPadding => Self::NoPadding,
107 PropertyName::NonNull => Self::NonNull,
108 PropertyName::Allocated => {
109 Self::check_arg_length(exprs.len(), 3, "Allocated");
110 let ty = Self::parse_type(tcx, def_id, &exprs[1], "Allocated");
111 let length = Self::parse_length(tcx, def_id, &exprs[2], "Allocated");
112 Self::Allocated(ty, length)
113 }
114 PropertyName::InBound => {
115 Self::check_arg_length(exprs.len(), 3, "InBound");
116 let ty = Self::parse_type(tcx, def_id, &exprs[1], "InBound");
117 let length = Self::parse_length(tcx, def_id, &exprs[2], "InBound");
118 Self::InBound(ty, length)
119 }
120 PropertyName::NonOverlap => Self::NonOverlap,
121 PropertyName::ValidNum => {
122 Self::check_arg_length(exprs.len(), 1, "ValidNum");
123 let bin_op = BinOp::Ne;
124 let length = Self::parse_length(tcx, def_id, &exprs[0], "ValidNum");
125 return Self::ValidNum(CisRange::new(bin_op, length));
126 }
127 PropertyName::ValidString => Self::ValidString,
128 PropertyName::ValidCStr => Self::ValidCStr,
129 PropertyName::Init => {
130 Self::check_arg_length(exprs.len(), 3, "Init");
131 let ty = Self::parse_type(tcx, def_id, &exprs[1], "Init");
132 let length = Self::parse_length(tcx, def_id, &exprs[2], "Init");
133 Self::Init(ty, length)
134 }
135 PropertyName::Unwrap => Self::Unwrap,
136 PropertyName::Typed => {
137 Self::check_arg_length(exprs.len(), 2, "Typed");
138 let ty = Self::parse_type(tcx, def_id, &exprs[1], "Typed");
139 Self::Typed(ty)
140 }
141 PropertyName::Owning => Self::Owning,
142 PropertyName::Alias => Self::Alias,
143 PropertyName::Alive => Self::Alive,
144 PropertyName::Pinned => Self::Pinned,
145 PropertyName::NonVolatile => Self::NonVolatile,
146 PropertyName::Opened => Self::Opened,
147 PropertyName::Trait => Self::Trait,
148 PropertyName::Unreachable => Self::Unreachable,
149 PropertyName::ValidPtr => {
150 Self::check_arg_length(exprs.len(), 3, "ValidPtr");
151 let ty = Self::parse_type(tcx, def_id, &exprs[1], "ValidPtr");
152 let length = Self::parse_length(tcx, def_id, &exprs[2], "ValidPtr");
153 Self::ValidPtr(ty, length)
154 }
155 PropertyName::Deref => Self::Deref,
156 PropertyName::Ptr2Ref => Self::Ptr2Ref,
157 PropertyName::Layout => Self::Layout,
158 PropertyName::Unknown => Self::Unknown,
159 }
160 }
161
162 pub fn new_patial_order(p: usize, op: BinOp) -> Self {
163 Self::ValidNum(CisRange::new(op, CisRangeItem::Var(p, Vec::new())))
164 }
165
166 pub fn new_obj_boundary(ty: Ty<'tcx>, len: CisRangeItem) -> Self {
167 Self::InBound(ty, len)
168 }
169
170 fn check_arg_length(expr_len: usize, required_len: usize, sp: &str) -> bool {
172 if expr_len != required_len {
173 panic!("Wrong args length for {:?} Tag!", sp);
174 }
175 true
176 }
177
178 fn parse_type(tcx: TyCtxt<'tcx>, def_id: DefId, expr: &Expr, sp: &str) -> Ty<'tcx> {
180 let ty_ident_full = access_ident_recursive(expr);
181 if ty_ident_full.is_none() {
182 rap_error!("Incorrect expression for the type of {:?} Tag!", sp);
183 }
184 let ty_ident = ty_ident_full.unwrap().0;
185 let ty = match_ty_with_ident(tcx, def_id, ty_ident);
186 if ty.is_none() {
187 rap_error!("Cannot get type in {:?} Tag!", sp);
188 }
189 return ty.unwrap();
190 }
191
192 fn parse_length(tcx: TyCtxt<'tcx>, def_id: DefId, expr: &Expr, sp: &str) -> CisRangeItem {
194 if let Some(var_len) = parse_expr_into_local_and_ty(tcx, def_id, expr) {
195 CisRangeItem::Var(var_len.0, var_len.1.iter().map(|(x, _)| *x).collect())
196 } else if parse_expr_into_number(expr).is_some() {
197 CisRangeItem::Value(parse_expr_into_number(expr).unwrap())
198 } else {
199 rap_error!("Range length error in {:?} Tag!", sp);
200 CisRangeItem::Unknown
201 }
202 }
203}
204
205#[derive(Debug, Clone)]
206pub struct ContractualInvariantState<'tcx> {
207 pub contracts: Vec<PropertyContract<'tcx>>,
208}
209
210impl<'tcx> ContractualInvariantState<'tcx> {
211 pub fn new_default() -> Self {
212 Self {
213 contracts: Vec::new(),
214 }
215 }
216
217 pub fn add_contract(&mut self, contract: PropertyContract<'tcx>) {
218 self.contracts.push(contract);
219 }
220
221 pub fn get_contracts_length(&self) -> usize {
222 self.contracts.len()
223 }
224}