rapx/analysis/safedrop/
drop.rs

1use super::graph::*;
2use rustc_middle::mir::SourceInfo;
3use std::usize;
4
5#[derive(Debug, Copy, Clone)]
6pub struct LocalSpot {
7    pub bb: Option<usize>,
8    pub local: Option<usize>,
9}
10
11impl LocalSpot {
12    pub fn new(bb: usize, local: usize) -> Self {
13        LocalSpot {
14            bb: Some(bb),
15            local: Some(local),
16        }
17    }
18    pub fn from_local(local: usize) -> Self {
19        LocalSpot {
20            bb: None,
21            local: Some(local),
22        }
23    }
24    pub fn default() -> Self {
25        LocalSpot {
26            bb: None,
27            local: None,
28        }
29    }
30}
31
32#[derive(Debug, Clone)]
33pub struct DropRecord {
34    pub value_index: usize,
35    pub is_dropped: bool,
36    pub drop_spot: LocalSpot,
37    pub prop_chain: Vec<usize>,
38    pub has_dropped_field: bool,
39}
40
41impl DropRecord {
42    pub fn new(value_index: usize, is_dropped: bool, drop_spot: LocalSpot) -> Self {
43        DropRecord {
44            value_index,
45            is_dropped,
46            drop_spot,
47            prop_chain: Vec::new(),
48            has_dropped_field: false,
49        }
50    }
51    pub fn false_record(value_index: usize) -> Self {
52        DropRecord {
53            value_index,
54            is_dropped: false,
55            drop_spot: LocalSpot::default(),
56            prop_chain: Vec::new(),
57            has_dropped_field: false,
58        }
59    }
60    pub fn from(value_index: usize, record: &DropRecord) -> Self {
61        DropRecord {
62            value_index,
63            is_dropped: record.is_dropped,
64            drop_spot: record.drop_spot.clone(),
65            prop_chain: record.prop_chain.clone(),
66            has_dropped_field: record.has_dropped_field,
67        }
68    }
69    pub fn clear(&mut self) {
70        self.is_dropped = false;
71        self.drop_spot = LocalSpot::default();
72        self.prop_chain.clear();
73        self.has_dropped_field = false;
74    }
75}
76
77impl<'tcx> SafeDropGraph<'tcx> {
78    /*
79     * Mark the node as dropped.
80     * flag_cleanup: used to distinguish if a bug occurs in the unwinding path.
81     */
82    pub fn add_to_drop_record(
83        &mut self,
84        value_idx: usize, // the value to be dropped
85        bb_idx: usize,    // the block via_idx is dropped
86        _info: &SourceInfo,
87        flag_cleanup: bool,
88    ) {
89        rap_debug!(
90            "add_to_drop_record: value_idx = {}, bb_idx = {}",
91            value_idx,
92            bb_idx
93        );
94        //Rc drop
95        if self.mop_graph.values[value_idx].is_ref_count() {
96            return;
97        }
98        if self.df_check(value_idx, bb_idx, self.mop_graph.span, flag_cleanup) {
99            return;
100        }
101        if !self.drop_record[value_idx].is_dropped {
102            let drop_spot = LocalSpot::new(bb_idx, self.mop_graph.values[value_idx].local);
103            self.drop_record[value_idx] = DropRecord::new(value_idx, true, drop_spot);
104            rap_debug!("{:?}", self.drop_record[value_idx]);
105            self.push_drop_info(value_idx, drop_spot);
106        }
107    }
108
109    pub fn push_drop_info(&mut self, value_idx: usize, drop_spot: LocalSpot) {
110        self.push_drop_bottom_up(value_idx, drop_spot);
111        self.push_drop_top_down(value_idx, drop_spot);
112        //self.push_drop_alias(value_idx, drop_spot);
113    }
114
115    pub fn push_drop_alias(&mut self, value_idx: usize, drop_spot: LocalSpot) {
116        rap_debug!("push_drop_alias: value_idx = {}", value_idx,);
117        if let Some(aliases) = self.mop_graph.get_alias_set(value_idx) {
118            for i in aliases {
119                if i != value_idx {
120                    self.drop_record[i] = DropRecord::new(i, true, drop_spot);
121                    self.drop_record[i].prop_chain = self.drop_record[value_idx].prop_chain.clone();
122                    self.drop_record[i].prop_chain.push(i);
123                    rap_debug!("{:?}", self.drop_record[i]);
124                }
125            }
126        }
127    }
128
129    ///drop the fields of the root node.
130    pub fn push_drop_top_down(&mut self, value_idx: usize, drop_spot: LocalSpot) {
131        rap_debug!("push_drop_top_down: value_idx = {}", value_idx);
132        let mut prop_chain = vec![value_idx];
133        for (_field_id, field_value_id) in self.mop_graph.values[value_idx].fields.clone() {
134            self.drop_record[field_value_id] = DropRecord::new(field_value_id, true, drop_spot);
135            prop_chain.push(field_value_id);
136            self.drop_record[field_value_id].prop_chain = prop_chain.clone();
137            rap_debug!("{:?}", self.drop_record[field_value_id]);
138            self.push_drop_top_down(field_value_id, drop_spot);
139        }
140    }
141
142    pub fn push_drop_bottom_up(&mut self, value_idx: usize, drop_spot: LocalSpot) {
143        rap_debug!("push_drop_bottom_up: value_idx = {}", value_idx);
144        let mut father = self.mop_graph.values[value_idx].father.clone();
145        let mut prop_chain = vec![value_idx];
146        while let Some(father_info) = father {
147            let father_idx = father_info.father_value_id;
148            self.drop_record[father_idx].has_dropped_field = true;
149            if !self.drop_record[father_idx].is_dropped {
150                prop_chain.push(father_idx);
151                self.drop_record[father_idx].prop_chain = prop_chain.clone();
152                self.drop_record[father_idx].drop_spot = drop_spot;
153            }
154            rap_debug!("{:?}", self.drop_record[father_idx]);
155            father = self.mop_graph.values[father_idx].father.clone();
156        }
157    }
158
159    pub fn fetch_drop_info(&mut self, value_idx: usize) {
160        self.fetch_drop_from_bottom(value_idx);
161        self.fetch_drop_from_top(value_idx);
162        self.fetch_drop_from_alias(value_idx);
163    }
164
165    pub fn clear_drop_info(&mut self, value_idx: usize) {
166        rap_debug!("clear_drop: value_idx = {}", value_idx);
167        self.drop_record[value_idx].clear();
168        self.clear_field_drop(value_idx);
169        self.clear_father_drop(value_idx);
170    }
171
172    pub fn clear_father_drop(&mut self, value_idx: usize) {
173        rap_debug!("clear_drop_father: value_idx = {}", value_idx);
174        // to fix: this is an over approximation.
175        let mut father = self.mop_graph.values[value_idx].father.clone();
176        while let Some(father_info) = father {
177            let father_idx = father_info.father_value_id;
178            if !self.drop_record[father_idx].is_dropped {
179                self.drop_record[father_idx].clear();
180            }
181            father = self.mop_graph.values[father_idx].father.clone();
182        }
183    }
184
185    pub fn clear_field_drop(&mut self, value_idx: usize) {
186        rap_debug!("clear_field_drop: value_idx = {}", value_idx);
187        for (_field_id, field_value_id) in self.mop_graph.values[value_idx].fields.clone() {
188            self.drop_record[field_value_id].clear();
189            self.clear_field_drop(field_value_id);
190        }
191    }
192
193    pub fn fetch_drop_from_bottom(&mut self, value_idx: usize) {
194        rap_debug!("fetch_drop_from_bottom: value_idx = {}", value_idx);
195        for (_field_id, field_value_id) in self.mop_graph.values[value_idx].fields.clone() {
196            rap_debug!("{:?}", self.drop_record[field_value_id]);
197            self.fetch_drop_from_alias(field_value_id);
198            if self.drop_record[field_value_id].is_dropped {
199                self.push_drop_bottom_up(
200                    field_value_id,
201                    self.drop_record[field_value_id].drop_spot,
202                );
203                rap_debug!("{:?}", self.drop_record[value_idx]);
204                break;
205            }
206            self.fetch_drop_from_bottom(field_value_id);
207        }
208    }
209
210    pub fn fetch_drop_from_top(&mut self, value_idx: usize) {
211        rap_debug!("fetch_drop_from_top: value_idx = {}", value_idx);
212        let mut father = self.mop_graph.values[value_idx].father.clone();
213        while let Some(father_info) = father {
214            let father_idx = father_info.father_value_id;
215            self.fetch_drop_from_alias(father_idx);
216            if self.drop_record[father_idx].is_dropped {
217                self.push_drop_top_down(father_idx, self.drop_record[father_idx].drop_spot);
218                rap_debug!("{:?}", self.drop_record[value_idx]);
219                break;
220            }
221            father = self.mop_graph.values[father_idx].father.clone();
222        }
223    }
224
225    pub fn fetch_drop_from_alias(&mut self, value_idx: usize) {
226        rap_debug!("fetch_drop_from_alias: value_idx = {}", value_idx);
227        if let Some(aliases) = self.mop_graph.get_alias_set(value_idx) {
228            for idx in aliases {
229                // set idx as dropped if any of its alias has been dropped.
230                if self.drop_record[idx].is_dropped {
231                    self.drop_record[value_idx] = self.drop_record[idx].clone();
232                    self.drop_record[value_idx].value_index = value_idx;
233                    self.drop_record[value_idx].prop_chain.push(value_idx);
234                }
235            }
236        }
237    }
238}