rapx/
lib.rs

1#![feature(rustc_private)]
2#![feature(box_patterns)]
3
4#[macro_use]
5pub mod utils;
6
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_interface;
20extern crate rustc_metadata;
21extern crate rustc_middle;
22extern crate rustc_public;
23extern crate rustc_session;
24extern crate rustc_span;
25extern crate rustc_target;
26extern crate thin_vec;
27use analysis::{
28    core::{
29        alias_analysis::{default::AliasAnalyzer, AAResultMapWrapper, AliasAnalysis},
30        api_dependency::default::ApiDependencyAnalyzer,
31        callgraph::{default::CallGraphAnalyzer, CallGraphAnalysis, CallGraphDisplay},
32        dataflow::{
33            default::DataFlowAnalyzer, Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper,
34        },
35        ownedheap_analysis::{default::OwnedHeapAnalyzer, OHAResultMapWrapper, OwnedHeapAnalysis},
36        range_analysis::{
37            default::RangeAnalyzer, PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis,
38        },
39        ssa_transform::SSATrans,
40    },
41    opt::Opt,
42    rcanary::rCanary,
43    safedrop::SafeDrop,
44    senryx::{CheckLevel, SenryxCheck},
45    test::Test,
46    unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
47    utils::show_mir::ShowMir,
48    Analysis,
49};
50use rustc_ast::ast;
51use rustc_driver::{Callbacks, Compilation};
52use rustc_interface::{
53    interface::{self, Compiler},
54    Config,
55};
56use rustc_middle::{ty::TyCtxt, util::Providers};
57use rustc_session::search_paths::PathKind;
58use std::path::PathBuf;
59use std::{env, sync::Arc};
60
61// Insert rustc arguments at the beginning of the argument list that RAP wants to be
62// set per default, for maximal validation power.
63pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
64
65/// This is the data structure to handle rapx options as a rustc callback.
66
67#[derive(Debug, Copy, Clone, Hash)]
68pub struct RapCallback {
69    alias: bool,
70    api_dependency: bool,
71    callgraph: bool,
72    dataflow: usize,
73    ownedheap: bool,
74    range: usize,
75    ssa: bool,
76    test: bool,
77    infer: bool,
78    opt: usize,
79    rcanary: bool,
80    safedrop: bool,
81    show_mir: bool,
82    unsafety_isolation: usize,
83    verify: bool,
84    verify_std: bool,
85}
86
87#[allow(clippy::derivable_impls)]
88impl Default for RapCallback {
89    fn default() -> Self {
90        Self {
91            alias: false,
92            api_dependency: false,
93            callgraph: false,
94            dataflow: 0,
95            ownedheap: false,
96            range: 0,
97            ssa: false,
98            test: false,
99            infer: false,
100            opt: usize::MAX,
101            rcanary: false,
102            safedrop: false,
103            show_mir: false,
104            unsafety_isolation: 0,
105            verify: false,
106            verify_std: false,
107        }
108    }
109}
110
111impl Callbacks for RapCallback {
112    fn config(&mut self, config: &mut Config) {
113        config.override_queries = Some(|_, providers| {
114            providers.extern_queries.used_crate_source = |tcx, cnum| {
115                let mut providers = Providers::default();
116                rustc_metadata::provide(&mut providers);
117                let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
118                // HACK: rustc will emit "crate ... required to be available in rlib format, but
119                // was not found in this form" errors once we use `tcx.dependency_formats()` if
120                // there's no rlib provided, so setting a dummy path here to workaround those errors.
121                Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
122                crate_source
123            };
124        });
125    }
126    fn after_crate_root_parsing(
127        &mut self,
128        _compiler: &interface::Compiler,
129        _krate: &mut ast::Crate,
130    ) -> Compilation {
131        preprocess::ssa_preprocess::create_ssa_struct(_krate);
132        Compilation::Continue
133    }
134    fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
135        rap_trace!("Execute after_analysis() of compiler callbacks");
136        rustc_public::rustc_internal::run(tcx, || {
137            start_analyzer(tcx, self);
138        })
139        .expect("Failed to run rustc_public.");
140        rap_trace!("analysis done");
141        Compilation::Continue
142    }
143}
144
145impl RapCallback {
146    /// Enable alias analysis. The parameter is used to config the threshold of alias analysis.
147    /// Currently, we mainly use it to control the depth of field-sensitive analysis.
148    /// -alias0: set field depth limit to 10; do not distinguish different flows within a each
149    /// strongly-connected component.
150    /// -alias1: set field depth limit to 20 (this is default setting).
151    /// -alias2: set field depth limit to 30.
152    pub fn enable_alias(&mut self, arg: String) {
153        self.alias = true;
154        match arg.as_str() {
155            "-alias" => {
156                env::set_var("ALIAS", "1");
157            }
158            "-alias0" => {
159                env::set_var("ALIAS", "0");
160            }
161            "-alias1" => {
162                env::set_var("ALIAS", "1");
163            }
164            "-alias2" => {
165                env::set_var("ALIAS", "2");
166            }
167            _ => {}
168        }
169    }
170
171    /// Test if alias analysis is enabled.
172    pub fn is_alias_enabled(&self) -> bool {
173        self.alias
174    }
175
176    /// Enable API-dependency graph generation.
177    pub fn enable_api_dependency(&mut self) {
178        self.api_dependency = true;
179    }
180
181    /// Test if API-dependency graph generation is enabled.
182    pub fn is_api_dependency_enabled(&self) -> bool {
183        self.api_dependency
184    }
185
186    /// Enable call-graph analysis.
187    pub fn enable_callgraph(&mut self) {
188        self.callgraph = true;
189    }
190
191    /// Test if call-graph analysis is enabled.
192    pub fn is_callgraph_enabled(&self) -> bool {
193        self.callgraph
194    }
195
196    /// Enable owned heap analysis.
197    pub fn enable_ownedheap(&mut self) {
198        self.ownedheap = true;
199    }
200
201    /// Test if owned-heap analysis is enabled.
202    pub fn is_ownedheap_enabled(&self) -> bool {
203        self.ownedheap
204    }
205
206    /// Enable dataflow analysis.
207    pub fn enable_dataflow(&mut self, x: usize) {
208        self.dataflow = x;
209    }
210
211    /// Test if dataflow analysis is enabled.
212    pub fn is_dataflow_enabled(&self) -> usize {
213        self.dataflow
214    }
215
216    /// Enable range analysis.
217    pub fn enable_range_analysis(&mut self, x: usize) {
218        self.range = x;
219    }
220
221    /// Test if range analysis is enabled.
222    pub fn is_range_analysis_enabled(&self) -> bool {
223        self.range > 0
224    }
225
226    /// Enable test of features provided by the core analysis traits.
227    pub fn enable_test(&mut self) {
228        self.test = true;
229    }
230
231    /// Check if test is enabled.
232    pub fn is_test_enabled(&self) -> bool {
233        self.test
234    }
235
236    /// Enable ssa transformation
237    pub fn enable_ssa_transform(&mut self) {
238        self.ssa = true;
239    }
240
241    /// Test if ssa transformation is enabled.
242    pub fn is_ssa_transform_enabled(&self) -> bool {
243        self.ssa
244    }
245
246    /// Enable optimization analysis for performance bug detection.
247    pub fn enable_opt(&mut self, x: usize) {
248        self.opt = x;
249    }
250
251    /// Test if optimization analysis is enabled.
252    pub fn is_opt_enabled(&self) -> usize {
253        self.opt
254    }
255
256    /// Enable rcanary for memory leakage detection.
257    pub fn enable_rcanary(&mut self) {
258        self.rcanary = true;
259    }
260
261    /// Test if rcanary is enabled.
262    pub fn is_rcanary_enabled(&self) -> bool {
263        self.rcanary
264    }
265
266    /// Enable safedrop for use-after-free bug detection.
267    /// Similar to alias analysis, the second parameter is to control the depth threshold for
268    /// field-sensitive analysis.
269    pub fn enable_safedrop(&mut self, arg: String) {
270        self.safedrop = true;
271        match arg.as_str() {
272            "-F" => {
273                env::set_var("SAFEDROP", "1");
274                env::set_var("MOP", "1");
275            }
276            "-F0" => {
277                env::set_var("SAFEDROP", "0");
278                env::set_var("MOP", "0");
279            }
280            "-F1" => {
281                env::set_var("SAFEDROP", "1");
282                env::set_var("MOP", "1");
283            }
284            "-F2" => {
285                env::set_var("SAFEDROP", "2");
286                env::set_var("MOP", "2");
287            }
288            "-uaf" => {
289                env::set_var("SAFEDROP", "1");
290                env::set_var("MOP", "1");
291            }
292            _ => {}
293        }
294    }
295
296    /// Test if safedrop is enabled.
297    pub fn is_safedrop_enabled(&self) -> bool {
298        self.safedrop
299    }
300
301    /// Enable mir display.
302    pub fn enable_show_mir(&mut self) {
303        self.show_mir = true;
304    }
305
306    /// Test if mir display is enabled.
307    pub fn is_show_mir_enabled(&self) -> bool {
308        self.show_mir
309    }
310
311    pub fn enable_unsafety_isolation(&mut self, x: usize) {
312        self.unsafety_isolation = x;
313    }
314
315    pub fn is_unsafety_isolation_enabled(&self) -> usize {
316        self.unsafety_isolation
317    }
318
319    pub fn enable_verify(&mut self) {
320        self.verify = true;
321    }
322
323    pub fn is_verify_enabled(&self) -> bool {
324        self.verify
325    }
326
327    pub fn enable_verify_std(&mut self) {
328        self.verify_std = true;
329    }
330
331    pub fn is_verify_std_enabled(&self) -> bool {
332        self.verify_std
333    }
334
335    pub fn enable_infer(&mut self) {
336        self.infer = true;
337    }
338
339    pub fn is_infer_enabled(&self) -> bool {
340        self.infer
341    }
342}
343
344/// Start the analysis with the features enabled.
345pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
346    def_id::init(tcx);
347    if callback.is_alias_enabled() {
348        let mut analyzer = AliasAnalyzer::new(tcx);
349        analyzer.run();
350        let alias = analyzer.get_local_fn_alias();
351        rap_info!("{}", AAResultMapWrapper(alias));
352    }
353
354    if callback.is_api_dependency_enabled() {
355        let mut analyzer = ApiDependencyAnalyzer::new(tcx);
356        analyzer.run();
357    }
358
359    if callback.is_callgraph_enabled() {
360        let mut analyzer = CallGraphAnalyzer::new(tcx);
361        analyzer.run();
362        let callgraph = analyzer.get_callgraph();
363        rap_info!(
364            "{}",
365            CallGraphDisplay {
366                graph: &callgraph,
367                tcx
368            }
369        );
370        //analyzer.display();
371    }
372
373    match callback.is_dataflow_enabled() {
374        1 => {
375            let mut analyzer = DataFlowAnalyzer::new(tcx, false);
376            analyzer.run();
377            let result = analyzer.get_all_arg2ret();
378            rap_info!("{}", Arg2RetMapWrapper(result));
379        }
380        2 => {
381            let mut analyzer = DataFlowAnalyzer::new(tcx, true);
382            analyzer.run();
383            let result = analyzer.get_all_dataflow();
384            rap_info!("{}", DataFlowGraphMapWrapper(result));
385        }
386        _ => {}
387    }
388
389    if callback.is_ownedheap_enabled() {
390        let mut analyzer = OwnedHeapAnalyzer::new(tcx);
391        analyzer.run();
392        let result = analyzer.get_all_items();
393        rap_info!("{}", OHAResultMapWrapper(result));
394    }
395
396    if callback.is_range_analysis_enabled() {
397        match callback.range {
398            1 => {
399                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
400                analyzer.run();
401                let result = analyzer.get_all_fn_ranges();
402                rap_info!("{}", RAResultMapWrapper(result));
403            }
404            2 => {
405                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, true);
406                analyzer.run();
407                let result = analyzer.get_all_fn_ranges();
408                rap_info!("{}", RAResultMapWrapper(result));
409            }
410            3 => {
411                let mut analyzer = RangeAnalyzer::<i128>::new(tcx, false);
412                analyzer.start_path_constraints_analysis();
413                let result = analyzer.get_all_path_constraints();
414                rap_info!("{}", PathConstraintMapWrapper(result));
415            }
416            _ => {}
417        }
418    }
419
420    if callback.is_test_enabled() {
421        let test = Test::new(tcx);
422        test.start();
423    }
424
425    match callback.is_opt_enabled() {
426        0 => Opt::new(tcx, 0).start(),
427        1 => Opt::new(tcx, 1).start(),
428        2 => Opt::new(tcx, 2).start(),
429        _ => {}
430    }
431
432    let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
433        let mut heap = OwnedHeapAnalyzer::new(tcx);
434        heap.run();
435        let adt_owner = heap.get_all_items();
436        let mut rcx = rCanary::new(tcx, adt_owner);
437        rcx.start();
438        Some(rcx)
439    } else {
440        None
441    };
442
443    if callback.is_safedrop_enabled() {
444        SafeDrop::new(tcx).start();
445    }
446
447    if callback.is_show_mir_enabled() {
448        ShowMir::new(tcx).start();
449    }
450
451    if callback.is_ssa_transform_enabled() {
452        SSATrans::new(tcx, false).start();
453    }
454
455    let x = callback.is_unsafety_isolation_enabled();
456    match x {
457        1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
458        2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
459        3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
460        4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
461        _ => {}
462    }
463
464    if callback.is_verify_enabled() {
465        let check_level = CheckLevel::Medium;
466        SenryxCheck::new(tcx, 2).start(check_level, true);
467    }
468
469    if callback.is_verify_std_enabled() {
470        SenryxCheck::new(tcx, 2).start_analyze_std_func();
471    }
472
473    if callback.is_infer_enabled() {
474        let check_level = CheckLevel::Medium;
475        SenryxCheck::new(tcx, 2).start(check_level, false);
476    }
477}