1#![feature(rustc_private)]
2#![feature(box_patterns)]
3#![feature(let_chains)]
4#[macro_use]
5pub mod utils;
6pub mod analysis;
7pub mod preprocess;
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_hir_pretty;
16extern crate rustc_index;
17extern crate rustc_interface;
18extern crate rustc_metadata;
19extern crate rustc_middle;
20extern crate rustc_session;
21extern crate rustc_span;
22extern crate rustc_target;
23extern crate stable_mir;
24extern crate thin_vec;
25use analysis::{
26 core::{
27 alias_analysis::{default::AliasAnalyzer, AAResultMapWrapper, AliasAnalysis},
28 api_dependency::default::ApiDependencyAnalyzer,
29 callgraph::{default::CallGraphAnalyzer, CallGraphAnalysis, CallGraphDisplay},
30 dataflow::{
31 default::DataFlowAnalyzer, Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper,
32 },
33 ownedheap_analysis::{default::OwnedHeapAnalyzer, OHAResultMapWrapper, OwnedHeapAnalysis},
34 range_analysis::{
35 default::RangeAnalyzer, PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis,
36 },
37 ssa_transform::SSATrans,
38 },
39 opt::Opt,
40 rcanary::rCanary,
41 safedrop::SafeDrop,
42 senryx::{CheckLevel, SenryxCheck},
43 test::Test,
44 unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
45 utils::show_mir::ShowMir,
46 Analysis,
47};
48use rustc_ast::ast;
49use rustc_driver::{Callbacks, Compilation};
50use rustc_interface::{
51 interface::{self, Compiler},
52 Config,
53};
54use rustc_middle::{ty::TyCtxt, util::Providers};
55use rustc_session::search_paths::PathKind;
56use std::path::PathBuf;
57use std::{env, sync::Arc};
58
59pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
62
63#[derive(Debug, Copy, Clone, Hash)]
66pub struct RapCallback {
67 alias: bool,
68 api_dependency: bool,
69 callgraph: bool,
70 dataflow: usize,
71 ownedheap: bool,
72 range: usize,
73 ssa: bool,
74 test: bool,
75 infer: bool,
76 opt: usize,
77 rcanary: bool,
78 safedrop: bool,
79 show_mir: bool,
80 unsafety_isolation: usize,
81 verify: bool,
82}
83
84#[allow(clippy::derivable_impls)]
85impl Default for RapCallback {
86 fn default() -> Self {
87 Self {
88 alias: false,
89 api_dependency: false,
90 callgraph: false,
91 dataflow: 0,
92 ownedheap: false,
93 range: 0,
94 ssa: false,
95 test: false,
96 infer: false,
97 opt: usize::MAX,
98 rcanary: false,
99 safedrop: false,
100 show_mir: false,
101 unsafety_isolation: 0,
102 verify: false,
103 }
104 }
105}
106
107impl Callbacks for RapCallback {
108 fn config(&mut self, config: &mut Config) {
109 config.override_queries = Some(|_, providers| {
110 providers.extern_queries.used_crate_source = |tcx, cnum| {
111 let mut providers = Providers::default();
112 rustc_metadata::provide(&mut providers);
113 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
114 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
118 crate_source
119 };
120 });
121 }
122 fn after_crate_root_parsing(
123 &mut self,
124 _compiler: &interface::Compiler,
125 _krate: &mut ast::Crate,
126 ) -> Compilation {
127 preprocess::ssa_preprocess::create_ssa_struct(_krate);
128 Compilation::Continue
129 }
130 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
131 rap_trace!("Execute after_analysis() of compiler callbacks");
132 start_analyzer(tcx, *self);
133 rap_trace!("analysis done");
134 Compilation::Continue
135 }
136}
137
138impl RapCallback {
139 pub fn enable_alias(&mut self, arg: String) {
146 self.alias = true;
147 match arg.as_str() {
148 "-alias" => {
149 env::set_var("ALIAS", "1");
150 }
151 "-alias0" => {
152 env::set_var("ALIAS", "0");
153 }
154 "-alias1" => {
155 env::set_var("ALIAS", "1");
156 }
157 "-alias2" => {
158 env::set_var("ALIAS", "2");
159 }
160 _ => {}
161 }
162 }
163
164 pub fn is_alias_enabled(&self) -> bool {
166 self.alias
167 }
168
169 pub fn enable_api_dependency(&mut self) {
171 self.api_dependency = true;
172 }
173
174 pub fn is_api_dependency_enabled(self) -> bool {
176 self.api_dependency
177 }
178
179 pub fn enable_callgraph(&mut self) {
181 self.callgraph = true;
182 }
183
184 pub fn is_callgraph_enabled(&self) -> bool {
186 self.callgraph
187 }
188
189 pub fn enable_ownedheap(&mut self) {
191 self.ownedheap = true;
192 }
193
194 pub fn is_ownedheap_enabled(self) -> bool {
196 self.ownedheap
197 }
198
199 pub fn enable_dataflow(&mut self, x: usize) {
201 self.dataflow = x;
202 }
203
204 pub fn is_dataflow_enabled(self) -> usize {
206 self.dataflow
207 }
208
209 pub fn enable_range_analysis(&mut self, x: usize) {
211 self.range = x;
212 }
213
214 pub fn is_range_analysis_enabled(self) -> bool {
216 self.range > 0
217 }
218
219 pub fn enable_test(&mut self) {
221 self.test = true;
222 }
223
224 pub fn is_test_enabled(self) -> bool {
226 self.test
227 }
228
229 pub fn enable_ssa_transform(&mut self) {
231 self.ssa = true;
232 }
233
234 pub fn is_ssa_transform_enabled(self) -> bool {
236 self.ssa
237 }
238
239 pub fn enable_opt(&mut self, x: usize) {
241 self.opt = x;
242 }
243
244 pub fn is_opt_enabled(self) -> usize {
246 self.opt
247 }
248
249 pub fn enable_rcanary(&mut self) {
251 self.rcanary = true;
252 }
253
254 pub fn is_rcanary_enabled(&self) -> bool {
256 self.rcanary
257 }
258
259 pub fn enable_safedrop(&mut self, arg: String) {
263 self.safedrop = true;
264 match arg.as_str() {
265 "-F" => {
266 env::set_var("SAFEDROP", "1");
267 env::set_var("MOP", "1");
268 }
269 "-F0" => {
270 env::set_var("SAFEDROP", "0");
271 env::set_var("MOP", "0");
272 }
273 "-F1" => {
274 env::set_var("SAFEDROP", "1");
275 env::set_var("MOP", "1");
276 }
277 "-F2" => {
278 env::set_var("SAFEDROP", "2");
279 env::set_var("MOP", "2");
280 }
281 "-uaf" => {
282 env::set_var("SAFEDROP", "1");
283 env::set_var("MOP", "1");
284 }
285 _ => {}
286 }
287 }
288
289 pub fn is_safedrop_enabled(&self) -> bool {
291 self.safedrop
292 }
293
294 pub fn enable_show_mir(&mut self) {
296 self.show_mir = true;
297 }
298
299 pub fn is_show_mir_enabled(&self) -> bool {
301 self.show_mir
302 }
303
304 pub fn enable_unsafety_isolation(&mut self, x: usize) {
305 self.unsafety_isolation = x;
306 }
307
308 pub fn is_unsafety_isolation_enabled(&self) -> usize {
309 self.unsafety_isolation
310 }
311
312 pub fn enable_verify(&mut self) {
313 self.verify = true;
314 }
315
316 pub fn is_verify_enabled(&self) -> bool {
317 self.verify
318 }
319
320 pub fn enable_infer(&mut self) {
321 self.infer = true;
322 }
323
324 pub fn is_infer_enabled(&self) -> bool {
325 self.infer
326 }
327}
328
329pub fn start_analyzer(tcx: TyCtxt, callback: RapCallback) {
331 if callback.is_alias_enabled() {
332 let mut analyzer = AliasAnalyzer::new(tcx);
333 analyzer.run();
334 let alias = analyzer.get_local_fn_alias();
335 rap_info!("{}", AAResultMapWrapper(alias));
336 }
337
338 if callback.is_api_dependency_enabled() {
339 let mut analyzer = ApiDependencyAnalyzer::new(tcx);
340 analyzer.run();
341 }
342
343 if callback.is_callgraph_enabled() {
344 let mut analyzer = CallGraphAnalyzer::new(tcx);
345 analyzer.run();
346 let callgraph = analyzer.get_callgraph();
347 rap_info!(
348 "{}",
349 CallGraphDisplay {
350 graph: &callgraph,
351 tcx
352 }
353 );
354 }
356
357 match callback.is_dataflow_enabled() {
358 1 => {
359 let mut analyzer = DataFlowAnalyzer::new(tcx, false);
360 analyzer.run();
361 let result = analyzer.get_all_arg2ret();
362 rap_info!("{}", Arg2RetMapWrapper(result));
363 }
364 2 => {
365 let mut analyzer = DataFlowAnalyzer::new(tcx, true);
366 analyzer.run();
367 let result = analyzer.get_all_dataflow();
368 rap_info!("{}", DataFlowGraphMapWrapper(result));
369 }
370 _ => {}
371 }
372
373 if callback.is_ownedheap_enabled() {
374 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
375 analyzer.run();
376 let result = analyzer.get_all_items();
377 rap_info!("{}", OHAResultMapWrapper(result));
378 }
379
380 if callback.is_range_analysis_enabled() {
381 match callback.range {
382 1 => {
383 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
384 analyzer.run();
385 let result = analyzer.get_all_fn_ranges();
386 rap_info!("{}", RAResultMapWrapper(result));
387 }
388 2 => {
389 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, true);
390 analyzer.run();
391 let result = analyzer.get_all_fn_ranges();
392 rap_info!("{}", RAResultMapWrapper(result));
393 }
394 3 => {
395 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
396 analyzer.start_path_constraints_analysis();
397 let result = analyzer.get_all_path_constraints();
398 rap_info!("{}", PathConstraintMapWrapper(result));
399 }
400 _ => {}
401 }
402 }
403
404 if callback.is_test_enabled() {
405 let test = Test::new(tcx);
406 test.start();
407 }
408
409 match callback.is_opt_enabled() {
410 0 => Opt::new(tcx, 0).start(),
411 1 => Opt::new(tcx, 1).start(),
412 2 => Opt::new(tcx, 2).start(),
413 _ => {}
414 }
415
416 let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
417 let mut heap = OwnedHeapAnalyzer::new(tcx);
418 heap.run();
419 let adt_owner = heap.get_all_items();
420 let mut rcx = rCanary::new(tcx, adt_owner);
421 rcx.start();
422 Some(rcx)
423 } else {
424 None
425 };
426
427 if callback.is_safedrop_enabled() {
428 SafeDrop::new(tcx).start();
429 }
430
431 if callback.is_show_mir_enabled() {
432 ShowMir::new(tcx).start();
433 }
434
435 if callback.is_ssa_transform_enabled() {
436 SSATrans::new(tcx, false).start();
437 }
438
439 let x = callback.is_unsafety_isolation_enabled();
440 match x {
441 1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
442 2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
443 3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
444 4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
445 _ => {}
446 }
447
448 if callback.is_verify_enabled() {
449 let check_level = CheckLevel::Medium;
450 SenryxCheck::new(tcx, 2).start(check_level, true);
451 }
452
453 if callback.is_infer_enabled() {
454 let check_level = CheckLevel::Medium;
455 SenryxCheck::new(tcx, 2).start(check_level, false);
456 }
457}