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::{core::alias_analysis::mfp::MfpAliasAnalyzer, scan::ScanAnalysis};
32use analysis::{
33 Analysis,
34 core::{
35 alias_analysis::{AliasAnalysis, FnAliasMapWrapper, default::AliasAnalyzer},
36 api_dependency::ApiDependencyAnalyzer,
37 callgraph::{CallGraphAnalysis, FnCallDisplay, default::CallGraphAnalyzer},
38 dataflow::{
39 Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper, default::DataFlowAnalyzer,
40 },
41 ownedheap_analysis::{OHAResultMapWrapper, OwnedHeapAnalysis, default::OwnedHeapAnalyzer},
42 range_analysis::{
43 PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis, default::RangeAnalyzer,
44 },
45 ssa_transform::SSATrans,
46 },
47 opt::Opt,
48 rcanary::rCanary,
49 safedrop::SafeDrop,
50 senryx::{CheckLevel, SenryxCheck},
51 test::Test,
52 upg::{TargetCrate, UPGAnalysis},
53 utils::show_mir::ShowMir,
54};
55use rustc_ast::ast;
56use rustc_driver::{Callbacks, Compilation};
57use rustc_interface::{
58 Config,
59 interface::{self, Compiler},
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] = &[
69 "-Zalways-encode-mir",
70 "-Zmir-opt-level=0",
71 "-Zinline-mir-threshold=0",
72 "-Zinline-mir-hint-threshold=0",
73 "-Zcross-crate-inline-threshold=0",
74];
75
76#[derive(Debug, Clone, Hash)]
79pub struct RapCallback {
80 alias: bool,
81 alias_mfp: bool,
82 api_dependency: bool,
83 callgraph: bool,
84 dataflow: usize,
85 ownedheap: bool,
86 range: usize,
87 ssa: bool,
88 test: bool,
89 infer: bool,
90 opt: usize,
91 rcanary: bool,
92 safedrop: bool,
93 show_mir: bool,
94 show_mir_dot: bool,
95 upg: usize,
96 verify: bool,
97 verify_std: bool,
98 scan: bool,
99 test_crate: Option<String>,
100}
101
102#[allow(clippy::derivable_impls)]
103impl Default for RapCallback {
104 fn default() -> Self {
105 Self {
106 alias: false,
107 alias_mfp: false,
108 api_dependency: false,
109 callgraph: false,
110 dataflow: 0,
111 ownedheap: false,
112 range: 0,
113 ssa: false,
114 test: false,
115 infer: false,
116 opt: usize::MAX,
117 rcanary: false,
118 safedrop: false,
119 show_mir: false,
120 show_mir_dot: false,
121 upg: 0,
122 verify: false,
123 verify_std: false,
124 scan: false,
125 test_crate: None,
126 }
127 }
128}
129
130impl Callbacks for RapCallback {
131 fn config(&mut self, config: &mut Config) {
132 config.override_queries = Some(|_, providers| {
133 providers.extern_queries.used_crate_source = |tcx, cnum| {
134 let mut providers = Providers::default();
135 rustc_metadata::provide(&mut providers);
136 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
137 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
141 crate_source
142 };
143 });
144 }
145
146 fn after_crate_root_parsing(
147 &mut self,
148 compiler: &interface::Compiler,
149 krate: &mut ast::Crate,
150 ) -> Compilation {
151 let build_std = compiler
152 .sess
153 .opts
154 .crate_name
155 .as_deref()
156 .map(|s| matches!(s, "core" | "std"))
157 .unwrap_or(false);
158 preprocess::dummy_fns::create_dummy_fns(krate, build_std);
159 preprocess::ssa_preprocess::create_ssa_struct(krate, build_std);
160 Compilation::Continue
161 }
162 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
163 rap_trace!("Execute after_analysis() of compiler callbacks");
164
165 rustc_public::rustc_internal::run(tcx, || {
166 def_id::init(tcx);
167 if self.is_building_test_crate() {
168 start_analyzer(tcx, self);
169 } else {
170 let package_name = std::env::var("CARGO_PKG_NAME")
171 .expect("cannot capture env var `CARGO_PKG_NAME`");
172 rap_trace!("skip analyzing package `{}`", package_name);
173 }
174 })
175 .expect("Failed to run rustc_public.");
176 rap_trace!("analysis done");
177
178 Compilation::Continue
179 }
180}
181
182impl RapCallback {
183 fn is_building_test_crate(&self) -> bool {
184 match &self.test_crate {
185 None => true,
186 Some(test_crate) => {
187 let test_crate: &str = test_crate;
188 let package_name = std::env::var("CARGO_PKG_NAME")
189 .expect("cannot capture env var `CARGO_PKG_NAME`");
190 package_name == test_crate
191 }
192 }
193 }
194
195 pub fn enable_alias(&mut self, arg: String) {
202 self.alias = true;
203 match arg.as_str() {
204 "-alias" => unsafe {
205 env::set_var("ALIAS", "1");
206 },
207 "-alias0" => unsafe {
208 env::set_var("ALIAS", "0");
209 },
210 "-alias1" => unsafe {
211 env::set_var("ALIAS", "1");
212 },
213 "-alias2" => unsafe {
214 env::set_var("ALIAS", "2");
215 },
216 _ => {}
217 }
218 }
219
220 pub fn is_alias_enabled(&self) -> bool {
222 self.alias
223 }
224
225 pub fn enable_alias_mfp(&mut self) {
226 self.alias_mfp = true;
227 }
228
229 pub fn is_alias_mfp_enabled(&self) -> bool {
230 self.alias_mfp
231 }
232
233 pub fn enable_api_dependency(&mut self) {
235 self.api_dependency = true;
236 }
237
238 pub fn is_api_dependency_enabled(&self) -> bool {
240 self.api_dependency
241 }
242
243 pub fn enable_callgraph(&mut self) {
245 self.callgraph = true;
246 }
247
248 pub fn is_callgraph_enabled(&self) -> bool {
250 self.callgraph
251 }
252
253 pub fn enable_ownedheap(&mut self) {
255 self.ownedheap = true;
256 }
257
258 pub fn is_ownedheap_enabled(&self) -> bool {
260 self.ownedheap
261 }
262
263 pub fn enable_dataflow(&mut self, x: usize) {
265 self.dataflow = x;
266 }
267
268 pub fn is_dataflow_enabled(&self) -> usize {
270 self.dataflow
271 }
272
273 pub fn enable_range_analysis(&mut self, x: usize) {
275 self.range = x;
276 }
277
278 pub fn is_range_analysis_enabled(&self) -> bool {
280 self.range > 0
281 }
282
283 pub fn enable_test(&mut self) {
285 self.test = true;
286 }
287
288 pub fn is_test_enabled(&self) -> bool {
290 self.test
291 }
292
293 pub fn enable_ssa_transform(&mut self) {
295 self.ssa = true;
296 }
297
298 pub fn is_ssa_transform_enabled(&self) -> bool {
300 self.ssa
301 }
302
303 pub fn enable_opt(&mut self, x: usize) {
305 self.opt = x;
306 }
307
308 pub fn is_opt_enabled(&self) -> usize {
310 self.opt
311 }
312
313 pub fn enable_rcanary(&mut self) {
315 self.rcanary = true;
316 }
317
318 pub fn is_rcanary_enabled(&self) -> bool {
320 self.rcanary
321 }
322
323 pub fn enable_safedrop(&mut self, arg: String) {
327 self.safedrop = true;
328 match arg.as_str() {
329 "-F" => {
330 unsafe {
331 env::set_var("SAFEDROP", "1");
332 }
333 unsafe {
334 env::set_var("MOP", "1");
335 }
336 }
337 "-F0" => {
338 unsafe {
339 env::set_var("SAFEDROP", "0");
340 }
341 unsafe {
342 env::set_var("MOP", "0");
343 }
344 }
345 "-F1" => {
346 unsafe {
347 env::set_var("SAFEDROP", "1");
348 }
349 unsafe {
350 env::set_var("MOP", "1");
351 }
352 }
353 "-F2" => {
354 unsafe {
355 env::set_var("SAFEDROP", "2");
356 }
357 unsafe {
358 env::set_var("MOP", "2");
359 }
360 }
361 "-uaf" => {
362 unsafe {
363 env::set_var("SAFEDROP", "1");
364 }
365 unsafe {
366 env::set_var("MOP", "1");
367 }
368 }
369 _ => {}
370 }
371 }
372
373 pub fn is_safedrop_enabled(&self) -> bool {
375 self.safedrop
376 }
377
378 pub fn enable_show_mir(&mut self) {
380 self.show_mir = true;
381 }
382
383 pub fn is_show_mir_enabled(&self) -> bool {
385 self.show_mir
386 }
387
388 pub fn enable_show_mir_dot(&mut self) {
389 self.show_mir_dot = true;
390 }
391
392 pub fn is_show_mir_dot_enabled(&self) -> bool {
393 self.show_mir_dot
394 }
395
396 pub fn enable_upg(&mut self, x: usize) {
397 self.upg = x;
398 }
399
400 pub fn is_upg_enabled(&self) -> usize {
401 self.upg
402 }
403
404 pub fn enable_verify(&mut self) {
405 self.verify = true;
406 }
407
408 pub fn is_verify_enabled(&self) -> bool {
409 self.verify
410 }
411
412 pub fn enable_verify_std(&mut self) {
413 self.verify_std = true;
414 }
415
416 pub fn is_verify_std_enabled(&self) -> bool {
417 self.verify_std
418 }
419
420 pub fn enable_infer(&mut self) {
421 self.infer = true;
422 }
423
424 pub fn is_infer_enabled(&self) -> bool {
425 self.infer
426 }
427
428 pub fn enable_scan(&mut self) {
429 self.scan = true;
430 }
431
432 pub fn is_scan_enabled(&self) -> bool {
433 self.scan
434 }
435
436 pub fn set_test_crate(&mut self, crate_name: impl ToString) {
437 self.test_crate = Some(crate_name.to_string())
438 }
439}
440
441pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
443 if callback.is_alias_enabled() {
444 let mut analyzer = AliasAnalyzer::new(tcx);
445 analyzer.run();
446 let alias = analyzer.get_local_fn_alias();
447 rap_info!("{}", FnAliasMapWrapper(alias));
448 }
449
450 if callback.is_alias_mfp_enabled() {
451 let mut analyzer = MfpAliasAnalyzer::new(tcx);
452 analyzer.run();
453 let alias = analyzer.get_local_fn_alias();
454 rap_info!("{}", FnAliasMapWrapper(alias));
455 }
456
457 if callback.is_api_dependency_enabled() {
458 let mut analyzer = ApiDependencyAnalyzer::new(
459 tcx,
460 analysis::core::api_dependency::Config {
461 pub_only: true,
462 resolve_generic: true,
463 ignore_const_generic: true,
464 },
465 );
466 analyzer.run();
467 }
468
469 if callback.is_callgraph_enabled() {
470 let mut analyzer = CallGraphAnalyzer::new(tcx);
471 analyzer.run();
472 let callgraph = analyzer.get_fn_calls();
473 rap_info!(
474 "{}",
475 FnCallDisplay {
476 fn_calls: &callgraph,
477 tcx
478 }
479 );
480 }
482
483 match callback.is_dataflow_enabled() {
484 1 => {
485 let mut analyzer = DataFlowAnalyzer::new(tcx, false);
486 analyzer.run();
487 let result = analyzer.get_all_arg2ret();
488 rap_info!("{}", Arg2RetMapWrapper(result));
489 }
490 2 => {
491 let mut analyzer = DataFlowAnalyzer::new(tcx, true);
492 analyzer.run();
493 let result = analyzer.get_all_dataflow();
494 rap_info!("{}", DataFlowGraphMapWrapper(result));
495 }
496 _ => {}
497 }
498
499 if callback.is_ownedheap_enabled() {
500 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
501 analyzer.run();
502 let result = analyzer.get_all_items();
503 rap_info!("{}", OHAResultMapWrapper(result));
504 }
505
506 if callback.is_range_analysis_enabled() {
507 match callback.range {
508 1 => {
509 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
510 analyzer.run();
511 let result = analyzer.get_all_fn_ranges();
512 rap_info!("{}", RAResultMapWrapper(result));
513 }
514 2 => {
515 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, true);
516 analyzer.run();
517 let result = analyzer.get_all_fn_ranges();
518 rap_info!("{}", RAResultMapWrapper(result));
519 }
520 3 => {
521 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
522 analyzer.start_path_constraints_analysis();
523 let result = analyzer.get_all_path_constraints();
524 rap_info!("{}", PathConstraintMapWrapper(result));
525 }
526 _ => {}
527 }
528 }
529
530 if callback.is_test_enabled() {
531 let test = Test::new(tcx);
532 test.start();
533 }
534
535 match callback.is_opt_enabled() {
536 0 => Opt::new(tcx, 0).start(),
537 1 => Opt::new(tcx, 1).start(),
538 2 => Opt::new(tcx, 2).start(),
539 _ => {}
540 }
541
542 let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
543 let mut heap = OwnedHeapAnalyzer::new(tcx);
544 heap.run();
545 let adt_owner = heap.get_all_items();
546 let mut rcx = rCanary::new(tcx, adt_owner);
547 rcx.start();
548 Some(rcx)
549 } else {
550 None
551 };
552
553 if callback.is_safedrop_enabled() {
554 SafeDrop::new(tcx).start();
555 }
556
557 if callback.is_show_mir_enabled() {
558 ShowMir::new(tcx).start();
559 }
560
561 if callback.is_show_mir_dot_enabled() {
562 ShowMir::new(tcx).start_generate_dot();
563 }
564
565 if callback.is_ssa_transform_enabled() {
566 SSATrans::new(tcx, false).start();
567 }
568
569 let x = callback.is_upg_enabled();
570 match x {
571 1 => UPGAnalysis::new(tcx).start(TargetCrate::Other),
572 2 => UPGAnalysis::new(tcx).start(TargetCrate::Std),
573 _ => {}
574 }
575
576 if callback.is_verify_enabled() {
577 let check_level = CheckLevel::Medium;
578 SenryxCheck::new(tcx, 2).start(check_level, true);
579 }
580
581 if callback.is_verify_std_enabled() {
582 SenryxCheck::new(tcx, 2).start_analyze_std_func();
583 }
585
586 if callback.is_infer_enabled() {
587 let check_level = CheckLevel::Medium;
588 SenryxCheck::new(tcx, 2).start(check_level, false);
589 }
590
591 if callback.is_scan_enabled() {
592 ScanAnalysis::new(tcx).run();
593 }
594}