rapx/analysis/safedrop/
bug_records.rs

1use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2use rustc_span::Span;
3
4use crate::rap_warn;
5use crate::utils::log::are_spans_in_same_file;
6use rustc_span::symbol::Symbol;
7
8use annotate_snippets::Level;
9use annotate_snippets::Renderer;
10use annotate_snippets::Snippet;
11
12use crate::utils::log::{
13    relative_pos_range, span_to_filename, span_to_line_number, span_to_source_code,
14};
15
16pub struct BugRecords {
17    pub df_bugs: FxHashMap<usize, Span>,
18    pub df_bugs_unwind: FxHashMap<usize, Span>,
19    pub uaf_bugs: FxHashSet<Span>,
20    pub dp_bugs: FxHashSet<Span>,
21    pub dp_bugs_unwind: FxHashSet<Span>,
22}
23
24impl BugRecords {
25    pub fn new() -> BugRecords {
26        BugRecords {
27            df_bugs: FxHashMap::default(),
28            df_bugs_unwind: FxHashMap::default(),
29            uaf_bugs: FxHashSet::default(),
30            dp_bugs: FxHashSet::default(),
31            dp_bugs_unwind: FxHashSet::default(),
32        }
33    }
34
35    pub fn is_bug_free(&self) -> bool {
36        self.df_bugs.is_empty()
37            && self.uaf_bugs.is_empty()
38            && self.dp_bugs.is_empty()
39            && self.dp_bugs_unwind.is_empty()
40    }
41
42    pub fn df_bugs_output(&self, fn_name: Symbol, span: Span) {
43        if !self.df_bugs.is_empty() {
44            rap_warn!("Double free detected in function {:}", fn_name);
45            let code_source = span_to_source_code(span);
46            let filename = span_to_filename(span);
47            let mut snippet = Snippet::source(&code_source)
48                .line_start(span_to_line_number(span))
49                .origin(&filename)
50                .fold(false);
51            for i in self.df_bugs.iter() {
52                //todo: remove this condition
53                if are_spans_in_same_file(span, *i.1) {
54                    snippet = snippet.annotation(
55                        Level::Warning
56                            .span(relative_pos_range(span, *i.1))
57                            .label("Double free detected."),
58                    );
59                }
60            }
61            let message = Level::Warning
62                .title("Double free detected.")
63                .snippet(snippet);
64            let renderer = Renderer::styled();
65            println!("{}", renderer.render(message));
66        }
67    }
68
69    pub fn uaf_bugs_output(&self, fn_name: Symbol, span: Span) {
70        if !self.uaf_bugs.is_empty() {
71            rap_warn!("Use after free detected in function {:?}", fn_name);
72            let code_source = span_to_source_code(span);
73            let filename = span_to_filename(span);
74            let mut snippet = Snippet::source(&code_source)
75                .line_start(span_to_line_number(span))
76                .origin(&filename)
77                .fold(true);
78            for i in self.uaf_bugs.iter() {
79                //todo: remove this condition
80                if are_spans_in_same_file(span, *i) {
81                    snippet = snippet.annotation(
82                        Level::Warning
83                            .span(relative_pos_range(span, *i))
84                            .label("Use after free detected."),
85                    );
86                }
87            }
88            let message = Level::Warning
89                .title("Use after free detected.")
90                .snippet(snippet);
91            let renderer = Renderer::styled();
92            println!("{}", renderer.render(message));
93        }
94    }
95
96    pub fn dp_bug_output(&self, fn_name: Symbol, span: Span) {
97        let code_source = span_to_source_code(span);
98        let filename = span_to_filename(span);
99        if !self.dp_bugs.is_empty() {
100            rap_warn!("Dangling pointer detected in function {:?}", fn_name);
101            let mut snippet = Snippet::source(&code_source)
102                .line_start(span_to_line_number(span))
103                .origin(&filename)
104                .fold(false);
105            for i in self.dp_bugs.iter() {
106                //todo: remove this condition
107                if are_spans_in_same_file(span, *i) {
108                    snippet = snippet.annotation(
109                        Level::Warning
110                            .span(relative_pos_range(span, *i))
111                            .label("Dangling pointer detected."),
112                    );
113                }
114            }
115            let message = Level::Warning
116                .title("Dangling pointer detected.")
117                .snippet(snippet);
118            let renderer = Renderer::styled();
119            println!("{}", renderer.render(message));
120        }
121        if !self.dp_bugs_unwind.is_empty() {
122            rap_warn!(
123                "Dangling pointer detected in function {:?} during unwinding.",
124                fn_name
125            );
126            let mut snippet = Snippet::source(&code_source)
127                .line_start(span_to_line_number(span))
128                .origin(&filename)
129                .fold(false);
130            for i in self.dp_bugs_unwind.iter() {
131                //todo: remove this condition
132                if are_spans_in_same_file(span, *i) {
133                    snippet = snippet.annotation(
134                        Level::Warning
135                            .span(relative_pos_range(span, *i))
136                            .label("Dangling pointer detected during unwinding."),
137                    );
138                }
139            }
140            let message = Level::Warning
141                .title("Dangling pointer detected during unwinding.")
142                .snippet(snippet);
143            let renderer = Renderer::styled();
144            println!("{}", renderer.render(message));
145        }
146    }
147}