1#![feature(rustc_private)]
2#![feature(box_patterns)]
3
4#[macro_use]
5pub mod utils;
6pub mod analysis;
7
8extern crate intervals;
9extern crate rustc_abi;
10extern crate rustc_ast;
11extern crate rustc_data_structures;
12extern crate rustc_driver;
13extern crate rustc_errors;
14extern crate rustc_hir;
15extern crate rustc_index;
16extern crate rustc_interface;
17extern crate rustc_metadata;
18extern crate rustc_middle;
19extern crate rustc_session;
20extern crate rustc_span;
21extern crate rustc_target;
22extern crate stable_mir;
23
24use analysis::{
25 core::{
26 alias_analysis::default::DefaultAlias,
27 api_dep::ApiDep,
28 call_graph::CallGraph,
29 dataflow::DataFlow,
30 heap_analysis::{default::DefaultHeapAnalysis, HeapAnalysis},
31 range_analysis::{DefaultRange, SSATrans},
32 },
33 opt::Opt,
34 rcanary::rCanary,
35 safedrop::SafeDrop,
36 senryx::{CheckLevel, SenryxCheck},
37 unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
38 utils::show_mir::ShowMir,
39 Analysis,
40};
41use rustc_driver::{Callbacks, Compilation};
42use rustc_interface::{interface::Compiler, Config};
43use rustc_middle::{ty::TyCtxt, util::Providers};
44use rustc_session::search_paths::PathKind;
45use std::path::PathBuf;
46use std::{env, sync::Arc};
47
48pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
51
52pub type Elapsed = (i64, i64);
53
54#[derive(Debug, Copy, Clone, Hash)]
55pub struct RapCallback {
56 rcanary: bool,
57 safedrop: bool,
58 verify: bool,
59 infer: bool,
60 unsafety_isolation: usize,
61 alias: bool,
62 callgraph: bool,
63 api_dep: bool,
64 show_mir: bool,
65 dataflow: usize,
66 opt: usize,
67 heap_item: bool,
68 ssa: bool,
69 range: bool,
70}
71
72#[allow(clippy::derivable_impls)]
73impl Default for RapCallback {
74 fn default() -> Self {
75 Self {
76 rcanary: false,
77 safedrop: false,
78 verify: false,
79 infer: false,
80 unsafety_isolation: 0,
81 alias: false,
82 callgraph: false,
83 api_dep: false,
84 show_mir: false,
85 dataflow: 0,
86 opt: usize::MAX,
87 heap_item: false,
88 ssa: false,
89 range: false,
90 }
91 }
92}
93
94impl Callbacks for RapCallback {
95 fn config(&mut self, config: &mut Config) {
96 config.override_queries = Some(|_, providers| {
97 providers.extern_queries.used_crate_source = |tcx, cnum| {
98 let mut providers = Providers::default();
99 rustc_metadata::provide(&mut providers);
100 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
101 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
105 crate_source
106 };
107 });
108 }
109
110 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
111 rap_trace!("Execute after_analysis() of compiler callbacks");
112 start_analyzer(tcx, *self);
113 rap_trace!("analysis done");
114 Compilation::Continue
115 }
116}
117
118impl RapCallback {
119 pub fn enable_rcanary(&mut self) {
120 self.rcanary = true;
121 }
122
123 pub fn is_rcanary_enabled(&self) -> bool {
124 self.rcanary
125 }
126
127 pub fn enable_alias(&mut self, arg: String) {
128 self.alias = true;
129 match arg.as_str() {
130 "-alias" => {
131 env::set_var("ALIAS", "1");
132 }
133 "-alias0" => {
134 env::set_var("ALIAS", "0");
135 }
136 "-alias1" => {
137 env::set_var("ALIAS", "1");
138 }
139 "-alias2" => {
140 env::set_var("ALIAS", "2");
141 }
142 _ => {}
143 }
144 }
145
146 pub fn is_alias_enabled(&self) -> bool {
147 self.alias
148 }
149
150 pub fn enable_safedrop(&mut self, arg: String) {
151 self.safedrop = true;
152 match arg.as_str() {
153 "-F" => {
154 env::set_var("SAFEDROP", "1");
155 env::set_var("MOP", "1");
156 }
157 "-F0" => {
158 env::set_var("SAFEDROP", "0");
159 env::set_var("MOP", "0");
160 }
161 "-F1" => {
162 env::set_var("SAFEDROP", "1");
163 env::set_var("MOP", "1");
164 }
165 "-F2" => {
166 env::set_var("SAFEDROP", "2");
167 env::set_var("MOP", "2");
168 }
169 "-uaf" => {
170 env::set_var("SAFEDROP", "1");
171 env::set_var("MOP", "1");
172 }
173 _ => {}
174 }
175 }
176
177 pub fn is_safedrop_enabled(&self) -> bool {
178 self.safedrop
179 }
180
181 pub fn enable_unsafety_isolation(&mut self, x: usize) {
182 self.unsafety_isolation = x;
183 }
184
185 pub fn is_unsafety_isolation_enabled(&self) -> usize {
186 self.unsafety_isolation
187 }
188
189 pub fn enable_api_dep(&mut self) {
190 self.api_dep = true;
191 }
192
193 pub fn is_api_dep_enabled(self) -> bool {
194 self.api_dep
195 }
196
197 pub fn enable_verify(&mut self) {
198 self.verify = true;
199 }
200
201 pub fn is_verify_enabled(&self) -> bool {
202 self.verify
203 }
204
205 pub fn enable_infer(&mut self) {
206 self.infer = true;
207 }
208
209 pub fn is_infer_enabled(&self) -> bool {
210 self.infer
211 }
212
213 pub fn enable_callgraph(&mut self) {
214 self.callgraph = true;
215 }
216
217 pub fn is_callgraph_enabled(&self) -> bool {
218 self.callgraph
219 }
220
221 pub fn enable_show_mir(&mut self) {
222 self.show_mir = true;
223 }
224
225 pub fn is_show_mir_enabled(&self) -> bool {
226 self.show_mir
227 }
228
229 pub fn enable_dataflow(&mut self, x: usize) {
230 self.dataflow = x;
231 }
232
233 pub fn is_dataflow_enabled(self) -> usize {
234 self.dataflow
235 }
236
237 pub fn enable_opt(&mut self, x: usize) {
238 self.opt = x;
239 }
240
241 pub fn is_opt_enabled(self) -> usize {
242 self.opt
243 }
244
245 pub fn enable_heap_item(&mut self) {
246 self.heap_item = true;
247 }
248
249 pub fn is_heap_item_enabled(self) -> bool {
250 self.heap_item
251 }
252 pub fn enable_ssa_transform(&mut self) {
253 self.ssa = true;
254 }
255 pub fn is_ssa_transform_enabled(self) -> bool {
256 self.ssa
257 }
258 pub fn enable_range_analysis(&mut self) {
259 self.range = true;
260 }
261 pub fn is_range_analysis_enabled(self) -> bool {
262 self.range
263 }
264}
265
266#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
267pub enum RapPhase {
268 Cleanup,
269 Cargo,
270 Rustc,
271 LLVM, }
273
274pub fn start_analyzer(tcx: TyCtxt, callback: RapCallback) {
275 let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
276 let mut heap = DefaultHeapAnalysis::new(tcx);
277 heap.run();
278 let adt_owner = heap.get_all_items();
279 let mut rcx = rCanary::new(tcx, adt_owner);
280 rcx.start();
281 Some(rcx)
282 } else {
283 None
284 };
285
286 if callback.is_alias_enabled() {
287 let mut alias = DefaultAlias::new(tcx);
288 alias.run();
289 }
290
291 if callback.is_safedrop_enabled() {
292 SafeDrop::new(tcx).start();
293 }
294
295 if callback.is_heap_item_enabled() {
296 let mut heap_analysis = DefaultHeapAnalysis::new(tcx);
297 heap_analysis.run();
298 heap_analysis.output();
299 }
300
301 let x = callback.is_unsafety_isolation_enabled();
302 match x {
303 1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
304 2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
305 3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
306 4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
307 _ => {}
308 }
309
310 if callback.is_verify_enabled() {
311 let check_level = CheckLevel::Medium;
312 SenryxCheck::new(tcx, 2).start(check_level, true);
313 }
314
315 if callback.is_infer_enabled() {
316 let check_level = CheckLevel::Medium;
317 SenryxCheck::new(tcx, 2).start(check_level, false);
318 }
319
320 if callback.is_show_mir_enabled() {
321 ShowMir::new(tcx).start();
322 }
323
324 if callback.is_api_dep_enabled() {
325 ApiDep::new(tcx).start();
326 }
327
328 match callback.is_dataflow_enabled() {
329 1 => DataFlow::new(tcx, false).start(),
330 2 => DataFlow::new(tcx, true).start(),
331 _ => {}
332 }
333
334 if callback.is_callgraph_enabled() {
335 CallGraph::new(tcx).start();
336 }
337
338 match callback.is_opt_enabled() {
339 0 => Opt::new(tcx, 0).start(),
340 1 => Opt::new(tcx, 1).start(),
341 2 => Opt::new(tcx, 2).start(),
342 _ => {}
343 }
344 if callback.is_ssa_transform_enabled() {
345 SSATrans::new(tcx, false).start();
346 }
347 if callback.is_range_analysis_enabled() {
348 let mut analyzer = DefaultRange::<i32>::new(tcx, false);
349 analyzer.run();
350 }
351}