1use super::graph::*;
2use crate::analysis::core::alias_analysis::default::{MopAAResultMap, block::Term};
3use rustc_middle::{
4 mir::{
5 Operand::{self, Constant, Copy, Move},
6 Place, TerminatorKind,
7 },
8 ty::{TyCtxt, TyKind, TypingEnv},
9};
10use std::{
11 collections::{HashMap, HashSet},
12 vec,
13};
14
15pub const VISIT_LIMIT: usize = 1000;
16
17impl<'tcx> SafeDropGraph<'tcx> {
18 pub fn drop_check(&mut self, bb_idx: usize, tcx: TyCtxt<'tcx>) {
20 let cur_block = self.mop_graph.blocks[bb_idx].clone();
21 let is_cleanup = cur_block.is_cleanup;
22 if let Term::Drop(drop) = cur_block.terminator {
23 rap_debug!("drop check bb: {}, {:?}", bb_idx, drop);
24 match drop.kind {
25 TerminatorKind::Drop {
26 ref place,
27 target: _,
28 unwind: _,
29 replace: _,
30 drop: _,
31 async_fut: _,
32 } => {
33 if !self.drop_heap_item_check(place, tcx) {
34 return;
35 }
36 let birth = self.mop_graph.blocks[bb_idx].scc.enter;
37 let local = self.projection(false, place.clone());
38 let info = drop.source_info.clone();
39 self.add_to_drop_record(local, local, birth, &info, false, bb_idx, is_cleanup);
40 }
41 TerminatorKind::Call {
42 func: _, ref args, ..
43 } => {
44 if args.len() > 0 {
45 let birth = self.mop_graph.blocks[bb_idx].scc.enter;
46 let place = match args[0].node {
47 Operand::Copy(place) => place,
48 Operand::Move(place) => place,
49 _ => {
50 rap_error!("Constant operand exists: {:?}", args[0]);
51 return;
52 }
53 };
54 let local = self.projection(false, place.clone());
55 let info = drop.source_info.clone();
56 self.add_to_drop_record(
57 local, local, birth, &info, false, bb_idx, is_cleanup,
58 );
59 }
60 }
61 _ => {}
62 }
63 }
64 }
65
66 pub fn drop_heap_item_check(&self, place: &Place<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
67 let place_ty = place.ty(&tcx.optimized_mir(self.mop_graph.def_id).local_decls, tcx);
68 match place_ty.ty.kind() {
69 TyKind::Adt(adtdef, ..) => match self.adt_owner.get(&adtdef.did()) {
70 None => true,
71 Some(owenr_unit) => {
72 let idx = match place_ty.variant_index {
73 Some(vdx) => vdx.index(),
74 None => 0,
75 };
76 if owenr_unit[idx].0.is_onheap() || owenr_unit[idx].1.contains(&true) {
77 true
78 } else {
79 false
80 }
81 }
82 },
83 _ => true,
84 }
85 }
86
87 pub fn split_check(&mut self, bb_idx: usize, tcx: TyCtxt<'tcx>, fn_map: &MopAAResultMap) {
88 let backup_values = self.mop_graph.values.clone(); let backup_constant = self.mop_graph.constants.clone();
91 let backup_alias_set = self.mop_graph.alias_set.clone();
92 let backup_drop_record = self.drop_record.clone();
93 self.check(bb_idx, tcx, fn_map);
94 self.mop_graph.values = backup_values;
96 self.mop_graph.constants = backup_constant;
97 self.mop_graph.alias_set = backup_alias_set;
98 self.drop_record = backup_drop_record;
99 }
100
101 pub fn split_check_with_cond(
102 &mut self,
103 bb_idx: usize,
104 path_discr_id: usize,
105 path_discr_val: usize,
106 tcx: TyCtxt<'tcx>,
107 fn_map: &MopAAResultMap,
108 ) {
109 let backup_values = self.mop_graph.values.clone(); let backup_constant = self.mop_graph.constants.clone();
112 let backup_alias_set = self.mop_graph.alias_set.clone();
113 let backup_drop_record = self.drop_record.clone();
114 self.mop_graph
116 .constants
117 .insert(path_discr_id, path_discr_val);
118 self.check(bb_idx, tcx, fn_map);
119 self.mop_graph.values = backup_values;
121 self.mop_graph.constants = backup_constant;
122 self.mop_graph.alias_set = backup_alias_set;
123 self.drop_record = backup_drop_record;
124 }
125
126 pub fn check(&mut self, bb_idx: usize, tcx: TyCtxt<'tcx>, fn_map: &MopAAResultMap) {
128 self.mop_graph.visit_times += 1;
129 if self.mop_graph.visit_times > VISIT_LIMIT {
130 return;
131 }
132 let scc_idx = self.mop_graph.blocks[bb_idx].scc.enter;
133 let cur_block = self.mop_graph.blocks[bb_idx].clone();
134 rap_debug!(
135 "Checking bb: {}, scc_idx: {}, scc: {:?}",
136 bb_idx,
137 scc_idx,
138 cur_block.scc.clone(),
139 );
140
141 self.alias_bb(self.mop_graph.blocks[bb_idx].scc.enter);
142 self.alias_bbcall(self.mop_graph.blocks[bb_idx].scc.enter, tcx, fn_map);
143 self.drop_check(self.mop_graph.blocks[bb_idx].scc.enter, tcx);
144 if bb_idx == scc_idx {
145 let mut paths_in_scc = vec![];
148
149 self.mop_graph.calculate_scc_order(
151 scc_idx,
152 bb_idx,
153 &mut cur_block.scc.clone().nodes,
154 &mut vec![],
155 &mut HashMap::new(),
156 &mut HashSet::new(),
157 &mut paths_in_scc,
158 );
159 rap_debug!("Paths in scc: {:?}", paths_in_scc);
160
161 let backup_values = self.mop_graph.values.clone(); let backup_constant = self.mop_graph.constants.clone();
163 let backup_alias_set = self.mop_graph.alias_set.clone();
164 for each_path in paths_in_scc {
165 self.mop_graph.alias_set = backup_alias_set.clone();
166 self.mop_graph.values = backup_values.clone();
167 self.mop_graph.constants = backup_constant.clone();
168
169 if !each_path.is_empty() {
170 for idx in each_path {
171 self.alias_bb(idx);
172 self.alias_bbcall(idx, tcx, fn_map);
173 self.drop_check(idx, tcx);
174 }
175 }
176 }
177 rap_debug!("cur_block.next: {:?}", cur_block.next);
179 match cur_block.next.len() {
180 0 => {
181 if Self::should_check(self.mop_graph.def_id) {
182 self.dp_check(cur_block.is_cleanup);
183 }
184 return;
185 }
186 1 => {
187 for next in cur_block.next {
192 self.check(next, tcx, fn_map);
193 }
194 return;
195 }
196 _ => {}
197 }
198 }
199 let mut single_target = false;
201 let mut sw_val = 0;
202 let mut sw_target = 0; let mut path_discr_id = 0; let mut sw_targets = None; if let Term::Switch(switch) = &cur_block.terminator
206 && cur_block.scc.nodes.is_empty()
207 {
208 rap_debug!("Handle switchInt in bb {:?}", cur_block);
209 if let TerminatorKind::SwitchInt {
210 ref discr,
211 ref targets,
212 } = switch.kind
213 {
214 rap_debug!("{:?}", switch);
215 rap_debug!("{:?}", self.mop_graph.constants);
216 match discr {
217 Copy(p) | Move(p) => {
218 let place = self.projection(false, *p);
219 let local_decls = &tcx.optimized_mir(self.mop_graph.def_id).local_decls;
220 let place_ty = (*p).ty(local_decls, tcx);
221 rap_debug!("place {:?}", place);
222 match place_ty.ty.kind() {
223 TyKind::Bool => {
224 rap_debug!("SwitchInt via Bool");
225 if let Some(constant) = self.mop_graph.constants.get(&place) {
226 if *constant != usize::MAX {
227 single_target = true;
228 sw_val = *constant;
229 }
230 }
231 path_discr_id = place;
232 sw_targets = Some(targets.clone());
233 }
234 _ => {
235 if let Some(father) = self
236 .mop_graph
237 .discriminants
238 .get(&self.mop_graph.values[place].local)
239 {
240 if let Some(constant) = self.mop_graph.constants.get(father) {
241 if *constant != usize::MAX {
242 single_target = true;
243 sw_val = *constant;
244 }
245 }
246 if self.mop_graph.values[place].local == place {
247 path_discr_id = *father;
248 sw_targets = Some(targets.clone());
249 }
250 }
251 }
252 }
253 }
254 Constant(c) => {
255 single_target = true;
256 let ty_env =
257 TypingEnv::post_analysis(self.mop_graph.tcx, self.mop_graph.def_id);
258 if let Some(val) =
259 c.const_.try_eval_target_usize(self.mop_graph.tcx, ty_env)
260 {
261 sw_val = val as usize;
262 }
263 }
264 }
265 if single_target {
266 for iter in targets.iter() {
271 if iter.0 as usize == sw_val {
272 sw_target = iter.1.as_usize();
273 break;
274 }
275 }
276 if sw_target == 0 {
281 let all_target = targets.all_targets();
282 sw_target = all_target[all_target.len() - 1].as_usize();
283 }
284 }
285 }
286 }
287 if single_target {
290 self.check(sw_target, tcx, fn_map);
291 } else {
292 if let Some(targets) = sw_targets {
294 for iter in targets.iter() {
295 if self.mop_graph.visit_times > VISIT_LIMIT {
296 continue;
297 }
298 let next_idx = iter.1.as_usize();
299 let path_discr_val = iter.0 as usize;
300 self.split_check_with_cond(
301 next_idx,
302 path_discr_id,
303 path_discr_val,
304 tcx,
305 fn_map,
306 );
307 }
308 let all_targets = targets.all_targets();
309 let next_idx = all_targets[all_targets.len() - 1].as_usize();
310 let path_discr_val = usize::MAX; self.split_check_with_cond(next_idx, path_discr_id, path_discr_val, tcx, fn_map);
312 } else {
313 for i in &cur_block.next {
314 if self.mop_graph.visit_times > VISIT_LIMIT {
315 continue;
316 }
317 let next_idx = i;
318 self.split_check(*next_idx, tcx, fn_map);
319 }
320 }
321 }
322 rap_debug!("Values: {:?}", self.mop_graph.values);
323 rap_debug!("Alias: {:?}", self.mop_graph.alias_set);
324 }
325}