rapx/check/safedrop/
drop.rs

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