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