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] = &[
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" => {
193                env::set_var("ALIAS", "1");
194            }
195            "-alias0" => {
196                env::set_var("ALIAS", "0");
197            }
198            "-alias1" => {
199                env::set_var("ALIAS", "1");
200            }
201            "-alias2" => {
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                env::set_var("SAFEDROP", "1");
311                env::set_var("MOP", "1");
312            }
313            "-F0" => {
314                env::set_var("SAFEDROP", "0");
315                env::set_var("MOP", "0");
316            }
317            "-F1" => {
318                env::set_var("SAFEDROP", "1");
319                env::set_var("MOP", "1");
320            }
321            "-F2" => {
322                env::set_var("SAFEDROP", "2");
323                env::set_var("MOP", "2");
324            }
325            "-uaf" => {
326                env::set_var("SAFEDROP", "1");
327                env::set_var("MOP", "1");
328            }
329            _ => {}
330        }
331    }
332
333    pub fn is_safedrop_enabled(&self) -> bool {
335        self.safedrop
336    }
337
338    pub fn enable_show_mir(&mut self) {
340        self.show_mir = true;
341    }
342
343    pub fn is_show_mir_enabled(&self) -> bool {
345        self.show_mir
346    }
347
348    pub fn enable_unsafety_isolation(&mut self, x: usize) {
349        self.unsafety_isolation = x;
350    }
351
352    pub fn is_unsafety_isolation_enabled(&self) -> usize {
353        self.unsafety_isolation
354    }
355
356    pub fn enable_verify(&mut self) {
357        self.verify = true;
358    }
359
360    pub fn is_verify_enabled(&self) -> bool {
361        self.verify
362    }
363
364    pub fn enable_verify_std(&mut self) {
365        self.verify_std = true;
366    }
367
368    pub fn is_verify_std_enabled(&self) -> bool {
369        self.verify_std
370    }
371
372    pub fn enable_infer(&mut self) {
373        self.infer = true;
374    }
375
376    pub fn is_infer_enabled(&self) -> bool {
377        self.infer
378    }
379
380    pub fn enable_scan(&mut self) {
381        self.scan = true;
382    }
383
384    pub fn is_scan_enabled(&self) -> bool {
385        self.scan
386    }
387
388    pub fn set_test_crate(&mut self, crate_name: impl ToString) {
389        self.test_crate = Some(crate_name.to_string())
390    }
391}
392
393pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
395    if callback.is_alias_enabled() {
396        let mut analyzer = AliasAnalyzer::new(tcx);
397        analyzer.run();
398        let alias = analyzer.get_local_fn_alias();
399        rap_info!("{}", AAResultMapWrapper(alias));
400    }
401
402    if callback.is_api_dependency_enabled() {
403        let mut analyzer = ApiDependencyAnalyzer::new(
404            tcx,
405            analysis::core::api_dependency::Config {
406                pub_only: true,
407                resolve_generic: true,
408                ignore_const_generic: true,
409            },
410        );
411        analyzer.run();
412    }
413
414    if callback.is_callgraph_enabled() {
415        let mut analyzer = CallGraphAnalyzer::new(tcx);
416        analyzer.run();
417        let callgraph = analyzer.get_callgraph();
418        rap_info!(
419            "{}",
420            CallGraphDisplay {
421                graph: &callgraph,
422                tcx
423            }
424        );
425        }
427
428    match callback.is_dataflow_enabled() {
429        1 => {
430            let mut analyzer = DataFlowAnalyzer::new(tcx, false);
431            analyzer.run();
432            let result = analyzer.get_all_arg2ret();
433            rap_info!("{}", Arg2RetMapWrapper(result));
434        }
435        2 => {
436            let mut analyzer = DataFlowAnalyzer::new(tcx, true);
437            analyzer.run();
438            let result = analyzer.get_all_dataflow();
439            rap_info!("{}", DataFlowGraphMapWrapper(result));
440        }
441        _ => {}
442    }
443
444    if callback.is_ownedheap_enabled() {
445        let mut analyzer = OwnedHeapAnalyzer::new(tcx);
446        analyzer.run();
447        let result = analyzer.get_all_items();
448        rap_info!("{}", OHAResultMapWrapper(result));
449    }
450
451    if callback.is_range_analysis_enabled() {
452        match callback.range {
453            1 => {
454                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
455                analyzer.run();
456                let result = analyzer.get_all_fn_ranges();
457                rap_info!("{}", RAResultMapWrapper(result));
458            }
459            2 => {
460                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, true);
461                analyzer.run();
462                let result = analyzer.get_all_fn_ranges();
463                rap_info!("{}", RAResultMapWrapper(result));
464            }
465            3 => {
466                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
467                analyzer.start_path_constraints_analysis();
468                let result = analyzer.get_all_path_constraints();
469                rap_info!("{}", PathConstraintMapWrapper(result));
470            }
471            _ => {}
472        }
473    }
474
475    if callback.is_test_enabled() {
476        let test = Test::new(tcx);
477        test.start();
478    }
479
480    match callback.is_opt_enabled() {
481        0 => Opt::new(tcx, 0).start(),
482        1 => Opt::new(tcx, 1).start(),
483        2 => Opt::new(tcx, 2).start(),
484        _ => {}
485    }
486
487    let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
488        let mut heap = OwnedHeapAnalyzer::new(tcx);
489        heap.run();
490        let adt_owner = heap.get_all_items();
491        let mut rcx = rCanary::new(tcx, adt_owner);
492        rcx.start();
493        Some(rcx)
494    } else {
495        None
496    };
497
498    if callback.is_safedrop_enabled() {
499        SafeDrop::new(tcx).start();
500    }
501
502    if callback.is_show_mir_enabled() {
503        ShowMir::new(tcx).start();
504    }
505
506    if callback.is_ssa_transform_enabled() {
507        SSATrans::new(tcx, false).start();
508    }
509
510    let x = callback.is_unsafety_isolation_enabled();
511    match x {
512        1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
513        2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
514        3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
515        4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
516        _ => {}
517    }
518
519    if callback.is_verify_enabled() {
520        let check_level = CheckLevel::Medium;
521        SenryxCheck::new(tcx, 2).start(check_level, true);
522    }
523
524    if callback.is_verify_std_enabled() {
525        SenryxCheck::new(tcx, 2).start_analyze_std_func();
526        }
528
529    if callback.is_infer_enabled() {
530        let check_level = CheckLevel::Medium;
531        SenryxCheck::new(tcx, 2).start(check_level, false);
532    }
533
534    if callback.is_scan_enabled() {
535        ScanAnalysis::new(tcx).run();
536    }
537}