rapx/
lib.rs

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