rapx/verify/property_checker/
transmute.rs1use rustc_middle::ty::{GenericArgKind, Ty, TyKind};
4use z3::Solver;
5
6use crate::verify::{
7 contract::{Property, PropertyArg},
8 report::CheckResult,
9};
10use crate::helpers::mir_scan::Checkpoint;
11use crate::verify::vm::state::VmState;
12
13use super::PropertyChecker;
14
15impl PropertyChecker {
16 pub(super) fn check_valid_transmute<'ctx, 'tcx>(&self, vm_state: &VmState<'ctx, 'tcx>, _solver: &Solver<'ctx>,
19 _checkpoint: &Checkpoint<'tcx>, property: &Property<'tcx>) -> CheckResult
20 {
21 let src = property.args().get(0).and_then(|a| if let PropertyArg::Ty(ty) = a { Some(*ty) } else { None });
22 let dst = property.args().get(1).and_then(|a| if let PropertyArg::Ty(ty) = a { Some(*ty) } else { None });
23 match (src, dst) {
24 (Some(s), Some(d)) if vm_state.size_of_ty(s) == vm_state.size_of_ty(d) => CheckResult::Proved,
25 (Some(s), Some(d)) => {
26 let ss = vm_state.size_of_ty(s);
27 let ds = vm_state.size_of_ty(d);
28 if ss == 0 || ds == 0 {
29 CheckResult::Proved
33 } else if ss == ds {
34 CheckResult::Proved
35 } else {
36 CheckResult::Failed
37 }
38 }
39 _ => CheckResult::Proved,
40 }
41 }
42
43 pub(super) fn check_trait<'ctx, 'tcx>(&self, vm_state: &VmState<'ctx, 'tcx>, _solver: &Solver<'ctx>,
46 checkpoint: &Checkpoint<'tcx>, property: &Property<'tcx>) -> CheckResult
47 {
48 let ty = match property.args().first() {
49 Some(PropertyArg::Ty(ty)) => *ty,
50 _ => return CheckResult::Unknown,
51 };
52 let trait_name = match property.args().get(1) {
53 Some(PropertyArg::Ident(name)) => name.as_str(),
54 _ => return CheckResult::Unknown,
55 };
56
57 let tcx = vm_state.tcx;
58
59 if trait_name == "Copy" {
60 let typing_env = rustc_middle::ty::TypingEnv::post_analysis(tcx, checkpoint.caller);
61 if tcx.type_is_copy_modulo_regions(typing_env, ty) {
62 return CheckResult::Proved;
63 }
64 let resolved = self.instantiate_callsite_ty(vm_state, checkpoint, ty);
66 if resolved != ty && tcx.type_is_copy_modulo_regions(typing_env, resolved) {
67 return CheckResult::Proved;
68 }
69 }
70
71 if trait_name == "Sized" {
72 if !ty.is_sized(tcx, rustc_middle::ty::TypingEnv::post_analysis(tcx, checkpoint.caller)) {
73 return CheckResult::Failed;
74 }
75 return CheckResult::Proved;
76 }
77
78 let predicates = crate::compat::predicates_of(tcx, checkpoint.caller);
79 #[cfg(not(rapx_ge_100))]
80 let pred_iter = predicates.predicates.iter();
81 #[cfg(rapx_ge_100)]
82 let pred_iter = predicates.clauses.iter();
83 for (predicate, _span) in pred_iter {
84 if let rustc_middle::ty::ClauseKind::Trait(trait_ref) = predicate.kind().skip_binder() {
85 if trait_ref.self_ty() == ty {
86 let def_path = tcx.def_path_str(trait_ref.def_id());
87 let short_name = def_path.rsplit("::").next().unwrap_or(&def_path);
88 if short_name == trait_name {
89 return CheckResult::Proved;
90 }
91 }
92 }
93 }
94
95 CheckResult::Unknown
96 }
97
98 pub(super) fn check_split_transmute<'ctx, 'tcx>(&self, vm_state: &VmState<'ctx, 'tcx>, _solver: &Solver<'ctx>,
101 checkpoint: &Checkpoint<'tcx>, property: &Property<'tcx>) -> CheckResult
102 {
103 if vm_state.contract_flags.split_transmute_asserted {
104 return CheckResult::Proved;
105 }
106 let src = property.args().get(0).and_then(|a| if let PropertyArg::Ty(ty) = a { Some(*ty) } else { None });
107 let dst = property.args().get(1).and_then(|a| if let PropertyArg::Ty(ty) = a { Some(*ty) } else { None });
108 let src = src.map(|ty| self.instantiate_callsite_ty(vm_state, checkpoint, ty));
109 let dst = dst.map(|ty| self.instantiate_callsite_ty(vm_state, checkpoint, ty));
110 match (src, dst) {
111 (Some(mut s), Some(mut d)) => {
112 if let TyKind::Slice(elem) = s.kind() {
117 s = *elem;
118 }
119 if let TyKind::Slice(elem) = d.kind() {
120 d = *elem;
121 }
122
123 if s == d {
126 return CheckResult::Proved;
127 }
128
129 if Self::is_simd_vector(vm_state, d) {
132 if let TyKind::Adt(_, args) = d.kind() {
133 if args.iter().any(|a| matches!(a.kind(), GenericArgKind::Type(t) if t == s)) {
134 return CheckResult::Proved;
135 }
136 }
137 }
138
139 let src_sz = Self::ty_size(vm_state, s);
140 let dst_sz = Self::ty_size(vm_state, d);
141 if src_sz == 0 || dst_sz == 0 { return CheckResult::Failed; }
142 if Self::all_bit_patterns_valid(d) {
149 return CheckResult::Proved;
150 }
151 CheckResult::Failed
152 }
153 _ => CheckResult::Failed,
154 }
155 }
156
157 fn is_simd_vector<'ctx, 'tcx>(vm_state: &VmState<'ctx, 'tcx>, ty: Ty<'tcx>) -> bool {
159 if let TyKind::Adt(adt_def, _) = ty.kind() {
160 let name = vm_state.tcx.item_name(adt_def.did());
161 if name.as_str() == "Simd" {
162 let path = vm_state.tcx.def_path_str(adt_def.did());
163 return path.contains("::simd::");
164 }
165 }
166 false
167 }
168
169 fn ty_size<'ctx, 'tcx>(vm_state: &VmState<'ctx, 'tcx>, ty: Ty<'tcx>) -> u64 {
171 let sz = vm_state.size_of_ty(ty);
172 if sz > 0 { return sz; }
173 let typing_env = rustc_middle::ty::TypingEnv::post_analysis(
175 vm_state.tcx, vm_state.caller_def_id);
176 let sz = crate::helpers::mir_utils::catch_panic(|| {
177 vm_state.tcx.layout_of(
178 rustc_middle::ty::PseudoCanonicalInput { typing_env, value: ty }
179 )
180 }).ok().and_then(|r| r.ok()).map(|l| l.size.bytes()).unwrap_or(0);
181 if sz > 0 { return sz; }
182 let generic_sz = crate::helpers::mir_utils::size_of_generic_param(vm_state.tcx, vm_state.caller_def_id, ty);
184 if generic_sz > 0 { return generic_sz; }
185 0
186 }
187
188 pub(super) fn all_bit_patterns_valid(ty: Ty<'_>) -> bool {
194 match ty.kind() {
195 rustc_middle::ty::TyKind::Uint(_) => true,
196 rustc_middle::ty::TyKind::Int(_) => true,
197 rustc_middle::ty::TyKind::Float(_) => true,
198 rustc_middle::ty::TyKind::RawPtr(..) => true,
199 rustc_middle::ty::TyKind::Tuple(elems) => {
200 elems.iter().all(|e| Self::all_bit_patterns_valid(e))
201 }
202 rustc_middle::ty::TyKind::Array(elem, _) => Self::all_bit_patterns_valid(*elem),
203 _ => false,
204 }
205 }
206}