1#![feature(rustc_private)]
2#![feature(box_patterns)]
3#![feature(macro_metavar_expr_concat)]
4
5#[macro_use]
6pub mod utils;
7pub mod analysis;
8pub mod def_id;
9pub mod preprocess;
10extern crate intervals;
11extern crate rustc_abi;
12extern crate rustc_ast;
13extern crate rustc_data_structures;
14extern crate rustc_driver;
15extern crate rustc_errors;
16extern crate rustc_hir;
17extern crate rustc_hir_pretty;
18extern crate rustc_index;
19extern crate rustc_infer;
20extern crate rustc_interface;
21extern crate rustc_metadata;
22extern crate rustc_middle;
23extern crate rustc_public;
24extern crate rustc_session;
25extern crate rustc_span;
26extern crate rustc_target;
27extern crate rustc_trait_selection;
28extern crate rustc_traits;
29extern crate rustc_type_ir;
30extern crate thin_vec;
31use crate::analysis::scan::ScanAnalysis;
32use analysis::{
33 core::{
34 alias_analysis::{default::AliasAnalyzer, AAResultMapWrapper, AliasAnalysis},
35 api_dependency::ApiDependencyAnalyzer,
36 callgraph::{default::CallGraphAnalyzer, CallGraphAnalysis, CallGraphDisplay},
37 dataflow::{
38 default::DataFlowAnalyzer, Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper,
39 },
40 ownedheap_analysis::{default::OwnedHeapAnalyzer, OHAResultMapWrapper, OwnedHeapAnalysis},
41 range_analysis::{
42 default::RangeAnalyzer, PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis,
43 },
44 ssa_transform::SSATrans,
45 },
46 opt::Opt,
47 rcanary::rCanary,
48 safedrop::SafeDrop,
49 senryx::{CheckLevel, SenryxCheck},
50 test::Test,
51 unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
52 utils::show_mir::ShowMir,
53 Analysis,
54};
55use rustc_ast::ast;
56use rustc_driver::{Callbacks, Compilation};
57use rustc_interface::{
58 interface::{self, Compiler},
59 Config,
60};
61use rustc_middle::{ty::TyCtxt, util::Providers};
62use rustc_session::search_paths::PathKind;
63use std::path::PathBuf;
64use std::{env, sync::Arc};
65
66pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
69
70#[derive(Debug, Clone, Hash)]
73pub struct RapCallback {
74 alias: bool,
75 api_dependency: bool,
76 callgraph: bool,
77 dataflow: usize,
78 ownedheap: bool,
79 range: usize,
80 ssa: bool,
81 test: bool,
82 infer: bool,
83 opt: usize,
84 rcanary: bool,
85 safedrop: bool,
86 show_mir: bool,
87 unsafety_isolation: usize,
88 verify: bool,
89 verify_std: bool,
90 scan: bool,
91 test_crate: Option<String>,
92}
93
94#[allow(clippy::derivable_impls)]
95impl Default for RapCallback {
96 fn default() -> Self {
97 Self {
98 alias: false,
99 api_dependency: false,
100 callgraph: false,
101 dataflow: 0,
102 ownedheap: false,
103 range: 0,
104 ssa: false,
105 test: false,
106 infer: false,
107 opt: usize::MAX,
108 rcanary: false,
109 safedrop: false,
110 show_mir: false,
111 unsafety_isolation: 0,
112 verify: false,
113 verify_std: false,
114 scan: false,
115 test_crate: None,
116 }
117 }
118}
119
120impl Callbacks for RapCallback {
121 fn config(&mut self, config: &mut Config) {
122 config.override_queries = Some(|_, providers| {
123 providers.extern_queries.used_crate_source = |tcx, cnum| {
124 let mut providers = Providers::default();
125 rustc_metadata::provide(&mut providers);
126 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
127 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
131 crate_source
132 };
133 });
134 }
135
136 fn after_crate_root_parsing(
137 &mut self,
138 _compiler: &interface::Compiler,
139 _krate: &mut ast::Crate,
140 ) -> Compilation {
141 preprocess::ssa_preprocess::create_ssa_struct(_krate);
142 Compilation::Continue
143 }
144 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
145 rap_trace!("Execute after_analysis() of compiler callbacks");
146
147 rustc_public::rustc_internal::run(tcx, || {
148 def_id::init(tcx);
149 if self.is_building_test_crate() {
150 start_analyzer(tcx, self);
151 } else {
152 let package_name = std::env::var("CARGO_PKG_NAME")
153 .expect("cannot capture env var `CARGO_PKG_NAME`");
154 rap_trace!("skip analyzing package `{}`", package_name);
155 }
156 })
157 .expect("Failed to run rustc_public.");
158 rap_trace!("analysis done");
159
160 Compilation::Continue
161 }
162}
163
164impl RapCallback {
165 fn is_building_test_crate(&self) -> bool {
166 match &self.test_crate {
167 None => true,
168 Some(test_crate) => {
169 let test_crate: &str = test_crate;
170 let package_name = std::env::var("CARGO_PKG_NAME")
171 .expect("cannot capture env var `CARGO_PKG_NAME`");
172 package_name == test_crate
173 }
174 }
175 }
176
177 pub fn enable_alias(&mut self, arg: String) {
184 self.alias = true;
185 match arg.as_str() {
186 "-alias" => {
187 env::set_var("ALIAS", "1");
188 }
189 "-alias0" => {
190 env::set_var("ALIAS", "0");
191 }
192 "-alias1" => {
193 env::set_var("ALIAS", "1");
194 }
195 "-alias2" => {
196 env::set_var("ALIAS", "2");
197 }
198 _ => {}
199 }
200 }
201
202 pub fn is_alias_enabled(&self) -> bool {
204 self.alias
205 }
206
207 pub fn enable_api_dependency(&mut self) {
209 self.api_dependency = true;
210 }
211
212 pub fn is_api_dependency_enabled(&self) -> bool {
214 self.api_dependency
215 }
216
217 pub fn enable_callgraph(&mut self) {
219 self.callgraph = true;
220 }
221
222 pub fn is_callgraph_enabled(&self) -> bool {
224 self.callgraph
225 }
226
227 pub fn enable_ownedheap(&mut self) {
229 self.ownedheap = true;
230 }
231
232 pub fn is_ownedheap_enabled(&self) -> bool {
234 self.ownedheap
235 }
236
237 pub fn enable_dataflow(&mut self, x: usize) {
239 self.dataflow = x;
240 }
241
242 pub fn is_dataflow_enabled(&self) -> usize {
244 self.dataflow
245 }
246
247 pub fn enable_range_analysis(&mut self, x: usize) {
249 self.range = x;
250 }
251
252 pub fn is_range_analysis_enabled(&self) -> bool {
254 self.range > 0
255 }
256
257 pub fn enable_test(&mut self) {
259 self.test = true;
260 }
261
262 pub fn is_test_enabled(&self) -> bool {
264 self.test
265 }
266
267 pub fn enable_ssa_transform(&mut self) {
269 self.ssa = true;
270 }
271
272 pub fn is_ssa_transform_enabled(&self) -> bool {
274 self.ssa
275 }
276
277 pub fn enable_opt(&mut self, x: usize) {
279 self.opt = x;
280 }
281
282 pub fn is_opt_enabled(&self) -> usize {
284 self.opt
285 }
286
287 pub fn enable_rcanary(&mut self) {
289 self.rcanary = true;
290 }
291
292 pub fn is_rcanary_enabled(&self) -> bool {
294 self.rcanary
295 }
296
297 pub fn enable_safedrop(&mut self, arg: String) {
301 self.safedrop = true;
302 match arg.as_str() {
303 "-F" => {
304 env::set_var("SAFEDROP", "1");
305 env::set_var("MOP", "1");
306 }
307 "-F0" => {
308 env::set_var("SAFEDROP", "0");
309 env::set_var("MOP", "0");
310 }
311 "-F1" => {
312 env::set_var("SAFEDROP", "1");
313 env::set_var("MOP", "1");
314 }
315 "-F2" => {
316 env::set_var("SAFEDROP", "2");
317 env::set_var("MOP", "2");
318 }
319 "-uaf" => {
320 env::set_var("SAFEDROP", "1");
321 env::set_var("MOP", "1");
322 }
323 _ => {}
324 }
325 }
326
327 pub fn is_safedrop_enabled(&self) -> bool {
329 self.safedrop
330 }
331
332 pub fn enable_show_mir(&mut self) {
334 self.show_mir = true;
335 }
336
337 pub fn is_show_mir_enabled(&self) -> bool {
339 self.show_mir
340 }
341
342 pub fn enable_unsafety_isolation(&mut self, x: usize) {
343 self.unsafety_isolation = x;
344 }
345
346 pub fn is_unsafety_isolation_enabled(&self) -> usize {
347 self.unsafety_isolation
348 }
349
350 pub fn enable_verify(&mut self) {
351 self.verify = true;
352 }
353
354 pub fn is_verify_enabled(&self) -> bool {
355 self.verify
356 }
357
358 pub fn enable_verify_std(&mut self) {
359 self.verify_std = true;
360 }
361
362 pub fn is_verify_std_enabled(&self) -> bool {
363 self.verify_std
364 }
365
366 pub fn enable_infer(&mut self) {
367 self.infer = true;
368 }
369
370 pub fn is_infer_enabled(&self) -> bool {
371 self.infer
372 }
373
374 pub fn enable_scan(&mut self) {
375 self.scan = true;
376 }
377
378 pub fn is_scan_enabled(&self) -> bool {
379 self.scan
380 }
381
382 pub fn set_test_crate(&mut self, crate_name: impl ToString) {
383 self.test_crate = Some(crate_name.to_string())
384 }
385}
386
387pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
389 if callback.is_alias_enabled() {
390 let mut analyzer = AliasAnalyzer::new(tcx);
391 analyzer.run();
392 let alias = analyzer.get_local_fn_alias();
393 rap_info!("{}", AAResultMapWrapper(alias));
394 }
395
396 if callback.is_api_dependency_enabled() {
397 let mut analyzer = ApiDependencyAnalyzer::new(
398 tcx,
399 analysis::core::api_dependency::Config {
400 pub_only: true,
401 resolve_generic: true,
402 ignore_const_generic: true,
403 },
404 );
405 analyzer.run();
406 }
407
408 if callback.is_callgraph_enabled() {
409 let mut analyzer = CallGraphAnalyzer::new(tcx);
410 analyzer.run();
411 let callgraph = analyzer.get_callgraph();
412 rap_info!(
413 "{}",
414 CallGraphDisplay {
415 graph: &callgraph,
416 tcx
417 }
418 );
419 }
421
422 match callback.is_dataflow_enabled() {
423 1 => {
424 let mut analyzer = DataFlowAnalyzer::new(tcx, false);
425 analyzer.run();
426 let result = analyzer.get_all_arg2ret();
427 rap_info!("{}", Arg2RetMapWrapper(result));
428 }
429 2 => {
430 let mut analyzer = DataFlowAnalyzer::new(tcx, true);
431 analyzer.run();
432 let result = analyzer.get_all_dataflow();
433 rap_info!("{}", DataFlowGraphMapWrapper(result));
434 }
435 _ => {}
436 }
437
438 if callback.is_ownedheap_enabled() {
439 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
440 analyzer.run();
441 let result = analyzer.get_all_items();
442 rap_info!("{}", OHAResultMapWrapper(result));
443 }
444
445 if callback.is_range_analysis_enabled() {
446 match callback.range {
447 1 => {
448 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
449 analyzer.run();
450 let result = analyzer.get_all_fn_ranges();
451 rap_info!("{}", RAResultMapWrapper(result));
452 }
453 2 => {
454 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, true);
455 analyzer.run();
456 let result = analyzer.get_all_fn_ranges();
457 rap_info!("{}", RAResultMapWrapper(result));
458 }
459 3 => {
460 let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
461 analyzer.start_path_constraints_analysis();
462 let result = analyzer.get_all_path_constraints();
463 rap_info!("{}", PathConstraintMapWrapper(result));
464 }
465 _ => {}
466 }
467 }
468
469 if callback.is_test_enabled() {
470 let test = Test::new(tcx);
471 test.start();
472 }
473
474 match callback.is_opt_enabled() {
475 0 => Opt::new(tcx, 0).start(),
476 1 => Opt::new(tcx, 1).start(),
477 2 => Opt::new(tcx, 2).start(),
478 _ => {}
479 }
480
481 let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
482 let mut heap = OwnedHeapAnalyzer::new(tcx);
483 heap.run();
484 let adt_owner = heap.get_all_items();
485 let mut rcx = rCanary::new(tcx, adt_owner);
486 rcx.start();
487 Some(rcx)
488 } else {
489 None
490 };
491
492 if callback.is_safedrop_enabled() {
493 SafeDrop::new(tcx).start();
494 }
495
496 if callback.is_show_mir_enabled() {
497 ShowMir::new(tcx).start();
498 }
499
500 if callback.is_ssa_transform_enabled() {
501 SSATrans::new(tcx, false).start();
502 }
503
504 let x = callback.is_unsafety_isolation_enabled();
505 match x {
506 1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
507 2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
508 3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
509 4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
510 _ => {}
511 }
512
513 if callback.is_verify_enabled() {
514 let check_level = CheckLevel::Medium;
515 SenryxCheck::new(tcx, 2).start(check_level, true);
516 }
517
518 if callback.is_verify_std_enabled() {
519 SenryxCheck::new(tcx, 2).start_analyze_std_func();
520 }
521
522 if callback.is_infer_enabled() {
523 let check_level = CheckLevel::Medium;
524 SenryxCheck::new(tcx, 2).start(check_level, false);
525 }
526
527 if callback.is_scan_enabled() {
528 ScanAnalysis::new(tcx).run();
529 }
530}