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 Analysis,
34 core::{
35 alias_analysis::{AAResultMapWrapper, AliasAnalysis, default::AliasAnalyzer},
36 api_dependency::ApiDependencyAnalyzer,
37 callgraph::{CallGraphAnalysis, CallGraphDisplay, 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 api_dependency: bool,
82 callgraph: bool,
83 dataflow: usize,
84 ownedheap: bool,
85 range: usize,
86 ssa: bool,
87 test: bool,
88 infer: bool,
89 opt: usize,
90 rcanary: bool,
91 safedrop: bool,
92 show_mir: bool,
93 show_mir_dot: bool,
94 upg: usize,
95 verify: bool,
96 verify_std: bool,
97 scan: bool,
98 test_crate: Option<String>,
99}
100
101#[allow(clippy::derivable_impls)]
102impl Default for RapCallback {
103 fn default() -> Self {
104 Self {
105 alias: false,
106 api_dependency: false,
107 callgraph: false,
108 dataflow: 0,
109 ownedheap: false,
110 range: 0,
111 ssa: false,
112 test: false,
113 infer: false,
114 opt: usize::MAX,
115 rcanary: false,
116 safedrop: false,
117 show_mir: false,
118 show_mir_dot: false,
119 upg: 0,
120 verify: false,
121 verify_std: false,
122 scan: false,
123 test_crate: None,
124 }
125 }
126}
127
128impl Callbacks for RapCallback {
129 fn config(&mut self, config: &mut Config) {
130 config.override_queries = Some(|_, providers| {
131 providers.extern_queries.used_crate_source = |tcx, cnum| {
132 let mut providers = Providers::default();
133 rustc_metadata::provide(&mut providers);
134 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
135 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
139 crate_source
140 };
141 });
142 }
143
144 fn after_crate_root_parsing(
145 &mut self,
146 _compiler: &interface::Compiler,
147 krate: &mut ast::Crate,
148 ) -> Compilation {
149 preprocess::dummy_fns::create_dummy_fns(krate);
150 preprocess::ssa_preprocess::create_ssa_struct(krate);
151 Compilation::Continue
152 }
153 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
154 rap_trace!("Execute after_analysis() of compiler callbacks");
155
156 rustc_public::rustc_internal::run(tcx, || {
157 def_id::init(tcx);
158 if self.is_building_test_crate() {
159 start_analyzer(tcx, self);
160 } else {
161 let package_name = std::env::var("CARGO_PKG_NAME")
162 .expect("cannot capture env var `CARGO_PKG_NAME`");
163 rap_trace!("skip analyzing package `{}`", package_name);
164 }
165 })
166 .expect("Failed to run rustc_public.");
167 rap_trace!("analysis done");
168
169 Compilation::Continue
170 }
171}
172
173impl RapCallback {
174 fn is_building_test_crate(&self) -> bool {
175 match &self.test_crate {
176 None => true,
177 Some(test_crate) => {
178 let test_crate: &str = test_crate;
179 let package_name = std::env::var("CARGO_PKG_NAME")
180 .expect("cannot capture env var `CARGO_PKG_NAME`");
181 package_name == test_crate
182 }
183 }
184 }
185
186 pub fn enable_alias(&mut self, arg: String) {
193 self.alias = true;
194 match arg.as_str() {
195 "-alias" => unsafe {
196 env::set_var("ALIAS", "1");
197 },
198 "-alias0" => unsafe {
199 env::set_var("ALIAS", "0");
200 },
201 "-alias1" => unsafe {
202 env::set_var("ALIAS", "1");
203 },
204 "-alias2" => unsafe {
205 env::set_var("ALIAS", "2");
206 },
207 _ => {}
208 }
209 }
210
211 pub fn is_alias_enabled(&self) -> bool {
213 self.alias
214 }
215
216 pub fn enable_api_dependency(&mut self) {
218 self.api_dependency = true;
219 }
220
221 pub fn is_api_dependency_enabled(&self) -> bool {
223 self.api_dependency
224 }
225
226 pub fn enable_callgraph(&mut self) {
228 self.callgraph = true;
229 }
230
231 pub fn is_callgraph_enabled(&self) -> bool {
233 self.callgraph
234 }
235
236 pub fn enable_ownedheap(&mut self) {
238 self.ownedheap = true;
239 }
240
241 pub fn is_ownedheap_enabled(&self) -> bool {
243 self.ownedheap
244 }
245
246 pub fn enable_dataflow(&mut self, x: usize) {
248 self.dataflow = x;
249 }
250
251 pub fn is_dataflow_enabled(&self) -> usize {
253 self.dataflow
254 }
255
256 pub fn enable_range_analysis(&mut self, x: usize) {
258 self.range = x;
259 }
260
261 pub fn is_range_analysis_enabled(&self) -> bool {
263 self.range > 0
264 }
265
266 pub fn enable_test(&mut self) {
268 self.test = true;
269 }
270
271 pub fn is_test_enabled(&self) -> bool {
273 self.test
274 }
275
276 pub fn enable_ssa_transform(&mut self) {
278 self.ssa = true;
279 }
280
281 pub fn is_ssa_transform_enabled(&self) -> bool {
283 self.ssa
284 }
285
286 pub fn enable_opt(&mut self, x: usize) {
288 self.opt = x;
289 }
290
291 pub fn is_opt_enabled(&self) -> usize {
293 self.opt
294 }
295
296 pub fn enable_rcanary(&mut self) {
298 self.rcanary = true;
299 }
300
301 pub fn is_rcanary_enabled(&self) -> bool {
303 self.rcanary
304 }
305
306 pub fn enable_safedrop(&mut self, arg: String) {
310 self.safedrop = true;
311 match arg.as_str() {
312 "-F" => {
313 unsafe {
314 env::set_var("SAFEDROP", "1");
315 }
316 unsafe {
317 env::set_var("MOP", "1");
318 }
319 }
320 "-F0" => {
321 unsafe {
322 env::set_var("SAFEDROP", "0");
323 }
324 unsafe {
325 env::set_var("MOP", "0");
326 }
327 }
328 "-F1" => {
329 unsafe {
330 env::set_var("SAFEDROP", "1");
331 }
332 unsafe {
333 env::set_var("MOP", "1");
334 }
335 }
336 "-F2" => {
337 unsafe {
338 env::set_var("SAFEDROP", "2");
339 }
340 unsafe {
341 env::set_var("MOP", "2");
342 }
343 }
344 "-uaf" => {
345 unsafe {
346 env::set_var("SAFEDROP", "1");
347 }
348 unsafe {
349 env::set_var("MOP", "1");
350 }
351 }
352 _ => {}
353 }
354 }
355
356 pub fn is_safedrop_enabled(&self) -> bool {
358 self.safedrop
359 }
360
361 pub fn enable_show_mir(&mut self) {
363 self.show_mir = true;
364 }
365
366 pub fn is_show_mir_enabled(&self) -> bool {
368 self.show_mir
369 }
370
371 pub fn enable_show_mir_dot(&mut self) {
372 self.show_mir_dot = true;
373 }
374
375 pub fn is_show_mir_dot_enabled(&self) -> bool {
376 self.show_mir_dot
377 }
378
379 pub fn enable_upg(&mut self, x: usize) {
380 self.upg = x;
381 }
382
383 pub fn is_upg_enabled(&self) -> usize {
384 self.upg
385 }
386
387 pub fn enable_verify(&mut self) {
388 self.verify = true;
389 }
390
391 pub fn is_verify_enabled(&self) -> bool {
392 self.verify
393 }
394
395 pub fn enable_verify_std(&mut self) {
396 self.verify_std = true;
397 }
398
399 pub fn is_verify_std_enabled(&self) -> bool {
400 self.verify_std
401 }
402
403 pub fn enable_infer(&mut self) {
404 self.infer = true;
405 }
406
407 pub fn is_infer_enabled(&self) -> bool {
408 self.infer
409 }
410
411 pub fn enable_scan(&mut self) {
412 self.scan = true;
413 }
414
415 pub fn is_scan_enabled(&self) -> bool {
416 self.scan
417 }
418
419 pub fn set_test_crate(&mut self, crate_name: impl ToString) {
420 self.test_crate = Some(crate_name.to_string())
421 }
422}
423
424pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
426 if callback.is_alias_enabled() {
427 let mut analyzer = AliasAnalyzer::new(tcx);
428 analyzer.run();
429 let alias = analyzer.get_local_fn_alias();
430 rap_info!("{}", AAResultMapWrapper(alias));
431 }
432
433 if callback.is_api_dependency_enabled() {
434 let mut analyzer = ApiDependencyAnalyzer::new(
435 tcx,
436 analysis::core::api_dependency::Config {
437 pub_only: true,
438 resolve_generic: true,
439 ignore_const_generic: true,
440 },
441 );
442 analyzer.run();
443 }
444
445 if callback.is_callgraph_enabled() {
446 let mut analyzer = CallGraphAnalyzer::new(tcx);
447 analyzer.run();
448 let callgraph = analyzer.get_callgraph();
449 rap_info!(
450 "{}",
451 CallGraphDisplay {
452 graph: &callgraph,
453 tcx
454 }
455 );
456 }
458
459 match callback.is_dataflow_enabled() {
460 1 => {
461 let mut analyzer = DataFlowAnalyzer::new(tcx, false);
462 analyzer.run();
463 let result = analyzer.get_all_arg2ret();
464 rap_info!("{}", Arg2RetMapWrapper(result));
465 }
466 2 => {
467 let mut analyzer = DataFlowAnalyzer::new(tcx, true);
468 analyzer.run();
469 let result = analyzer.get_all_dataflow();
470 rap_info!("{}", DataFlowGraphMapWrapper(result));
471 }
472 _ => {}
473 }
474
475 if callback.is_ownedheap_enabled() {
476 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
477 analyzer.run();
478 let result = analyzer.get_all_items();
479 rap_info!("{}", OHAResultMapWrapper(result));
480 }
481
482 if callback.is_range_analysis_enabled() {
483 match callback.range {
484 1 => {
485 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
486 analyzer.run();
487 let result = analyzer.get_all_fn_ranges();
488 rap_info!("{}", RAResultMapWrapper(result));
489 }
490 2 => {
491 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, true);
492 analyzer.run();
493 let result = analyzer.get_all_fn_ranges();
494 rap_info!("{}", RAResultMapWrapper(result));
495 }
496 3 => {
497 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
498 analyzer.start_path_constraints_analysis();
499 let result = analyzer.get_all_path_constraints();
500 rap_info!("{}", PathConstraintMapWrapper(result));
501 }
502 _ => {}
503 }
504 }
505
506 if callback.is_test_enabled() {
507 let test = Test::new(tcx);
508 test.start();
509 }
510
511 match callback.is_opt_enabled() {
512 0 => Opt::new(tcx, 0).start(),
513 1 => Opt::new(tcx, 1).start(),
514 2 => Opt::new(tcx, 2).start(),
515 _ => {}
516 }
517
518 let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
519 let mut heap = OwnedHeapAnalyzer::new(tcx);
520 heap.run();
521 let adt_owner = heap.get_all_items();
522 let mut rcx = rCanary::new(tcx, adt_owner);
523 rcx.start();
524 Some(rcx)
525 } else {
526 None
527 };
528
529 if callback.is_safedrop_enabled() {
530 SafeDrop::new(tcx).start();
531 }
532
533 if callback.is_show_mir_enabled() {
534 ShowMir::new(tcx).start();
535 }
536
537 if callback.is_show_mir_dot_enabled() {
538 ShowMir::new(tcx).start_generate_dot();
539 }
540
541 if callback.is_ssa_transform_enabled() {
542 SSATrans::new(tcx, false).start();
543 }
544
545 let x = callback.is_upg_enabled();
546 match x {
547 1 => UPGAnalysis::new(tcx).start(TargetCrate::Other),
548 2 => UPGAnalysis::new(tcx).start(TargetCrate::Std),
549 _ => {}
550 }
551
552 if callback.is_verify_enabled() {
553 let check_level = CheckLevel::Medium;
554 SenryxCheck::new(tcx, 2).start(check_level, true);
555 }
556
557 if callback.is_verify_std_enabled() {
558 SenryxCheck::new(tcx, 2).start_analyze_std_func();
559 }
561
562 if callback.is_infer_enabled() {
563 let check_level = CheckLevel::Medium;
564 SenryxCheck::new(tcx, 2).start(check_level, false);
565 }
566
567 if callback.is_scan_enabled() {
568 ScanAnalysis::new(tcx).run();
569 }
570}