rapx/verify/property_checker/
transmute.rs1use rustc_middle::ty::{GenericArgKind, Ty, TyKind};
4
5use crate::helpers::mir_scan::Checkpoint;
6use crate::verify::vm::state::VmState;
7use crate::verify::{
8 contract::{Property, PropertyArg},
9 report::{CheckResult, UnknownReason},
10};
11
12use super::PropertyChecker;
13
14impl PropertyChecker {
15 pub(super) fn check_valid_transmute<'z3, 'tcx>(
18 &self,
19 vm_state: &VmState<'z3, 'tcx>,
20 property: &Property<'tcx>,
21 ) -> CheckResult {
22 let src = Self::ty_arg(property, 0);
23 let dst = Self::ty_arg(property, 1);
24 match (src, dst) {
25 (Some(s), Some(d)) if vm_state.size_of_ty(s) == vm_state.size_of_ty(d) => {
26 CheckResult::ProvedByRule
27 }
28 (Some(s), Some(d)) => {
29 let ss = vm_state.size_of_ty(s);
30 let ds = vm_state.size_of_ty(d);
31 if ss == 0 || ds == 0 {
32 CheckResult::ProvedByRule
36 } else if ss == ds {
37 CheckResult::ProvedByRule
38 } else {
39 CheckResult::Failed
40 }
41 }
42 _ => CheckResult::ProvedByRule,
43 }
44 }
45
46 pub(super) fn check_trait<'z3, 'tcx>(
49 &self,
50 vm_state: &VmState<'z3, 'tcx>,
51 checkpoint: &Checkpoint<'tcx>,
52 property: &Property<'tcx>,
53 ) -> CheckResult {
54 let ty = match property.args().first() {
55 Some(PropertyArg::Ty(ty)) => *ty,
56 _ => return CheckResult::Unknown(UnknownReason::Unimplemented),
57 };
58 let trait_name = match property.args().get(1) {
59 Some(PropertyArg::Ident(name)) => name.as_str(),
60 _ => return CheckResult::Unknown(UnknownReason::Unimplemented),
61 };
62
63 let tcx = vm_state.tcx;
64
65 if trait_name == "Copy" {
66 let typing_env = rustc_middle::ty::TypingEnv::post_analysis(tcx, checkpoint.caller);
67 if tcx.type_is_copy_modulo_regions(typing_env, ty) {
68 return CheckResult::ProvedByRule;
69 }
70 let resolved = self.instantiate_callsite_ty(vm_state, checkpoint, ty);
72 if resolved != ty && tcx.type_is_copy_modulo_regions(typing_env, resolved) {
73 return CheckResult::ProvedByRule;
74 }
75 }
76
77 if trait_name == "Sized" {
78 if !ty.is_sized(
79 tcx,
80 rustc_middle::ty::TypingEnv::post_analysis(tcx, checkpoint.caller),
81 ) {
82 return CheckResult::Failed;
83 }
84 return CheckResult::ProvedByRule;
85 }
86
87 let predicates = crate::compat::predicates_of(tcx, checkpoint.caller);
88 #[cfg(not(rapx_ge_100))]
89 let pred_iter = predicates.predicates.iter();
90 #[cfg(rapx_ge_100)]
91 let pred_iter = predicates.clauses.iter();
92 for (predicate, _span) in pred_iter {
93 if let rustc_middle::ty::ClauseKind::Trait(trait_ref) = predicate.kind().skip_binder() {
94 if trait_ref.self_ty() == ty {
95 let short_name = crate::helpers::name::short_fn_name(tcx, trait_ref.def_id());
96 if short_name == trait_name {
97 return CheckResult::ProvedByRule;
98 }
99 }
100 }
101 }
102
103 if trait_name == "Copy" {
108 return CheckResult::Failed;
109 }
110 CheckResult::Unknown(UnknownReason::Unimplemented)
111 }
112
113 pub(super) fn check_split_transmute<'z3, 'tcx>(
116 &self,
117 vm_state: &VmState<'z3, 'tcx>,
118 checkpoint: &Checkpoint<'tcx>,
119 property: &Property<'tcx>,
120 ) -> CheckResult {
121 if vm_state.path_facts.split_transmute_asserted {
122 return CheckResult::ProvedByRule;
123 }
124 let src = Self::ty_arg(property, 0);
125 let dst = Self::ty_arg(property, 1);
126 let src = src.map(|ty| self.instantiate_callsite_ty(vm_state, checkpoint, ty));
127 let dst = dst.map(|ty| self.instantiate_callsite_ty(vm_state, checkpoint, ty));
128 match (src, dst) {
129 (Some(mut s), Some(mut d)) => {
130 if let TyKind::Slice(elem) = s.kind() {
135 s = *elem;
136 }
137 if let TyKind::Slice(elem) = d.kind() {
138 d = *elem;
139 }
140
141 if s == d {
144 return CheckResult::ProvedByRule;
145 }
146
147 if Self::is_simd_vector(vm_state, d) {
150 if let TyKind::Adt(_, args) = d.kind() {
151 if args
152 .iter()
153 .any(|a| matches!(a.kind(), GenericArgKind::Type(t) if t == s))
154 {
155 return CheckResult::ProvedByRule;
156 }
157 }
158 }
159
160 let src_sz = Self::ty_size(vm_state, s);
161 let dst_sz = Self::ty_size(vm_state, d);
162 if src_sz == 0 || dst_sz == 0 {
163 return CheckResult::Failed;
164 }
165 if Self::all_bit_patterns_valid(d) {
172 return CheckResult::ProvedByRule;
173 }
174 CheckResult::Failed
175 }
176 _ => CheckResult::Failed,
177 }
178 }
179
180 fn is_simd_vector<'z3, 'tcx>(_vm_state: &VmState<'z3, 'tcx>, ty: Ty<'tcx>) -> bool {
183 if let TyKind::Adt(adt_def, _) = ty.kind() {
184 return adt_def.repr().simd();
185 }
186 false
187 }
188
189 fn ty_size<'z3, 'tcx>(vm_state: &VmState<'z3, 'tcx>, ty: Ty<'tcx>) -> u64 {
191 let sz = vm_state.size_of_ty(ty);
192 if sz > 0 {
193 return sz;
194 }
195 let typing_env =
197 rustc_middle::ty::TypingEnv::post_analysis(vm_state.tcx, vm_state.current_frame.current_def_id);
198 let sz = crate::helpers::mir_utils::catch_panic(|| {
199 vm_state
200 .tcx
201 .layout_of(rustc_middle::ty::PseudoCanonicalInput {
202 typing_env,
203 value: ty,
204 })
205 })
206 .ok()
207 .and_then(|r| r.ok())
208 .map(|l| l.size.bytes())
209 .unwrap_or(0);
210 if sz > 0 {
211 return sz;
212 }
213 let generic_sz = crate::helpers::mir_utils::size_of_generic_param(
215 vm_state.tcx,
216 vm_state.current_frame.current_def_id,
217 ty,
218 );
219 if generic_sz > 0 {
220 return generic_sz;
221 }
222 0
223 }
224
225 pub(super) fn all_bit_patterns_valid(ty: Ty<'_>) -> bool {
231 match ty.kind() {
232 rustc_middle::ty::TyKind::Uint(_) => true,
233 rustc_middle::ty::TyKind::Int(_) => true,
234 rustc_middle::ty::TyKind::Float(_) => true,
235 rustc_middle::ty::TyKind::RawPtr(..) => true,
236 rustc_middle::ty::TyKind::Tuple(elems) => {
237 elems.iter().all(|e| Self::all_bit_patterns_valid(e))
238 }
239 rustc_middle::ty::TyKind::Array(elem, _) => Self::all_bit_patterns_valid(*elem),
240 _ => false,
241 }
242 }
243}