rapx/
lib.rs

1#![feature(rustc_private)]
2#![feature(box_patterns)]
3#![feature(let_chains)]
4#[macro_use]
5pub mod utils;
6pub mod analysis;
7pub mod preprocess;
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 stable_mir;
24extern crate thin_vec;
25use analysis::{
26    core::{
27        alias_analysis::{default::AliasAnalyzer, AAResultMapWrapper, AliasAnalysis},
28        api_dependency::default::ApiDependencyAnalyzer,
29        callgraph::{default::CallGraphAnalyzer, CallGraphAnalysis, CallGraphDisplay},
30        dataflow::{
31            default::DataFlowAnalyzer, Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper,
32        },
33        ownedheap_analysis::{default::OwnedHeapAnalyzer, OHAResultMapWrapper, OwnedHeapAnalysis},
34        range_analysis::{
35            default::RangeAnalyzer, PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis,
36        },
37        ssa_transform::SSATrans,
38    },
39    opt::Opt,
40    rcanary::rCanary,
41    safedrop::SafeDrop,
42    senryx::{CheckLevel, SenryxCheck},
43    test::Test,
44    unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
45    utils::show_mir::ShowMir,
46    Analysis,
47};
48use rustc_ast::ast;
49use rustc_driver::{Callbacks, Compilation};
50use rustc_interface::{
51    interface::{self, Compiler},
52    Config,
53};
54use rustc_middle::{ty::TyCtxt, util::Providers};
55use rustc_session::search_paths::PathKind;
56use std::path::PathBuf;
57use std::{env, sync::Arc};
58
59// Insert rustc arguments at the beginning of the argument list that RAP wants to be
60// set per default, for maximal validation power.
61pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
62
63/// This is the data structure to handle rapx options as a rustc callback.
64
65#[derive(Debug, Copy, Clone, Hash)]
66pub struct RapCallback {
67    alias: bool,
68    api_dependency: bool,
69    callgraph: bool,
70    dataflow: usize,
71    ownedheap: bool,
72    range: usize,
73    ssa: bool,
74    test: bool,
75    infer: bool,
76    opt: usize,
77    rcanary: bool,
78    safedrop: bool,
79    show_mir: bool,
80    unsafety_isolation: usize,
81    verify: bool,
82}
83
84#[allow(clippy::derivable_impls)]
85impl Default for RapCallback {
86    fn default() -> Self {
87        Self {
88            alias: false,
89            api_dependency: false,
90            callgraph: false,
91            dataflow: 0,
92            ownedheap: false,
93            range: 0,
94            ssa: false,
95            test: false,
96            infer: false,
97            opt: usize::MAX,
98            rcanary: false,
99            safedrop: false,
100            show_mir: false,
101            unsafety_isolation: 0,
102            verify: false,
103        }
104    }
105}
106
107impl Callbacks for RapCallback {
108    fn config(&mut self, config: &mut Config) {
109        config.override_queries = Some(|_, providers| {
110            providers.extern_queries.used_crate_source = |tcx, cnum| {
111                let mut providers = Providers::default();
112                rustc_metadata::provide(&mut providers);
113                let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
114                // HACK: rustc will emit "crate ... required to be available in rlib format, but
115                // was not found in this form" errors once we use `tcx.dependency_formats()` if
116                // there's no rlib provided, so setting a dummy path here to workaround those errors.
117                Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
118                crate_source
119            };
120        });
121    }
122    fn after_crate_root_parsing(
123        &mut self,
124        _compiler: &interface::Compiler,
125        _krate: &mut ast::Crate,
126    ) -> Compilation {
127        preprocess::ssa_preprocess::create_ssa_struct(_krate);
128        Compilation::Continue
129    }
130    fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
131        rap_trace!("Execute after_analysis() of compiler callbacks");
132        start_analyzer(tcx, *self);
133        rap_trace!("analysis done");
134        Compilation::Continue
135    }
136}
137
138impl RapCallback {
139    /// Enable alias analysis. The parameter is used to config the threshold of alias analysis.
140    /// Currently, we mainly use it to control the depth of field-sensitive analysis.
141    /// -alias0: set field depth limit to 10; do not distinguish different flows within a each
142    /// strongly-connected component.
143    /// -alias1: set field depth limit to 20 (this is default setting).
144    /// -alias2: set field depth limit to 30.
145    pub fn enable_alias(&mut self, arg: String) {
146        self.alias = true;
147        match arg.as_str() {
148            "-alias" => {
149                env::set_var("ALIAS", "1");
150            }
151            "-alias0" => {
152                env::set_var("ALIAS", "0");
153            }
154            "-alias1" => {
155                env::set_var("ALIAS", "1");
156            }
157            "-alias2" => {
158                env::set_var("ALIAS", "2");
159            }
160            _ => {}
161        }
162    }
163
164    /// Test if alias analysis is enabled.
165    pub fn is_alias_enabled(&self) -> bool {
166        self.alias
167    }
168
169    /// Enable API-dependency graph generation.
170    pub fn enable_api_dependency(&mut self) {
171        self.api_dependency = true;
172    }
173
174    /// Test if API-dependency graph generation is enabled.
175    pub fn is_api_dependency_enabled(self) -> bool {
176        self.api_dependency
177    }
178
179    /// Enable call-graph analysis.
180    pub fn enable_callgraph(&mut self) {
181        self.callgraph = true;
182    }
183
184    /// Test if call-graph analysis is enabled.
185    pub fn is_callgraph_enabled(&self) -> bool {
186        self.callgraph
187    }
188
189    /// Enable owned heap analysis.
190    pub fn enable_ownedheap(&mut self) {
191        self.ownedheap = true;
192    }
193
194    /// Test if owned-heap analysis is enabled.
195    pub fn is_ownedheap_enabled(self) -> bool {
196        self.ownedheap
197    }
198
199    /// Enable dataflow analysis.
200    pub fn enable_dataflow(&mut self, x: usize) {
201        self.dataflow = x;
202    }
203
204    /// Test if dataflow analysis is enabled.
205    pub fn is_dataflow_enabled(self) -> usize {
206        self.dataflow
207    }
208
209    /// Enable range analysis.
210    pub fn enable_range_analysis(&mut self, x: usize) {
211        self.range = x;
212    }
213
214    /// Test if range analysis is enabled.
215    pub fn is_range_analysis_enabled(self) -> bool {
216        self.range > 0
217    }
218
219    /// Enable test of features provided by the core analysis traits.
220    pub fn enable_test(&mut self) {
221        self.test = true;
222    }
223
224    /// Check if test is enabled.
225    pub fn is_test_enabled(self) -> bool {
226        self.test
227    }
228
229    /// Enable ssa transformation
230    pub fn enable_ssa_transform(&mut self) {
231        self.ssa = true;
232    }
233
234    /// Test if ssa transformation is enabled.
235    pub fn is_ssa_transform_enabled(self) -> bool {
236        self.ssa
237    }
238
239    /// Enable optimization analysis for performance bug detection.
240    pub fn enable_opt(&mut self, x: usize) {
241        self.opt = x;
242    }
243
244    /// Test if optimization analysis is enabled.
245    pub fn is_opt_enabled(self) -> usize {
246        self.opt
247    }
248
249    /// Enable rcanary for memory leakage detection.
250    pub fn enable_rcanary(&mut self) {
251        self.rcanary = true;
252    }
253
254    /// Test if rcanary is enabled.
255    pub fn is_rcanary_enabled(&self) -> bool {
256        self.rcanary
257    }
258
259    /// Enable safedrop for use-after-free bug detection.
260    /// Similar to alias analysis, the second parameter is to control the depth threshold for
261    /// field-sensitive analysis.
262    pub fn enable_safedrop(&mut self, arg: String) {
263        self.safedrop = true;
264        match arg.as_str() {
265            "-F" => {
266                env::set_var("SAFEDROP", "1");
267                env::set_var("MOP", "1");
268            }
269            "-F0" => {
270                env::set_var("SAFEDROP", "0");
271                env::set_var("MOP", "0");
272            }
273            "-F1" => {
274                env::set_var("SAFEDROP", "1");
275                env::set_var("MOP", "1");
276            }
277            "-F2" => {
278                env::set_var("SAFEDROP", "2");
279                env::set_var("MOP", "2");
280            }
281            "-uaf" => {
282                env::set_var("SAFEDROP", "1");
283                env::set_var("MOP", "1");
284            }
285            _ => {}
286        }
287    }
288
289    /// Test if safedrop is enabled.
290    pub fn is_safedrop_enabled(&self) -> bool {
291        self.safedrop
292    }
293
294    /// Enable mir display.
295    pub fn enable_show_mir(&mut self) {
296        self.show_mir = true;
297    }
298
299    /// Test if mir display is enabled.
300    pub fn is_show_mir_enabled(&self) -> bool {
301        self.show_mir
302    }
303
304    pub fn enable_unsafety_isolation(&mut self, x: usize) {
305        self.unsafety_isolation = x;
306    }
307
308    pub fn is_unsafety_isolation_enabled(&self) -> usize {
309        self.unsafety_isolation
310    }
311
312    pub fn enable_verify(&mut self) {
313        self.verify = true;
314    }
315
316    pub fn is_verify_enabled(&self) -> bool {
317        self.verify
318    }
319
320    pub fn enable_infer(&mut self) {
321        self.infer = true;
322    }
323
324    pub fn is_infer_enabled(&self) -> bool {
325        self.infer
326    }
327}
328
329/// Start the analysis with the features enabled.
330pub fn start_analyzer(tcx: TyCtxt, callback: RapCallback) {
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}