rapx/
lib.rs

1#![feature(rustc_private)]
2#![feature(box_patterns)]
3
4#[macro_use]
5pub mod utils;
6pub mod analysis;
7
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_index;
16extern crate rustc_interface;
17extern crate rustc_metadata;
18extern crate rustc_middle;
19extern crate rustc_session;
20extern crate rustc_span;
21extern crate rustc_target;
22extern crate stable_mir;
23
24use analysis::{
25    core::{
26        alias_analysis::default::DefaultAlias,
27        api_dep::ApiDep,
28        call_graph::CallGraph,
29        dataflow::DataFlow,
30        heap_analysis::{default::DefaultHeapAnalysis, HeapAnalysis},
31        range_analysis::{DefaultRange, SSATrans},
32    },
33    opt::Opt,
34    rcanary::rCanary,
35    safedrop::SafeDrop,
36    senryx::{CheckLevel, SenryxCheck},
37    unsafety_isolation::{UigInstruction, UnsafetyIsolationCheck},
38    utils::show_mir::ShowMir,
39    Analysis,
40};
41use rustc_driver::{Callbacks, Compilation};
42use rustc_interface::{interface::Compiler, Config};
43use rustc_middle::{ty::TyCtxt, util::Providers};
44use rustc_session::search_paths::PathKind;
45use std::path::PathBuf;
46use std::{env, sync::Arc};
47
48// Insert rustc arguments at the beginning of the argument list that RAP wants to be
49// set per default, for maximal validation power.
50pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
51
52pub type Elapsed = (i64, i64);
53
54#[derive(Debug, Copy, Clone, Hash)]
55pub struct RapCallback {
56    rcanary: bool,
57    safedrop: bool,
58    verify: bool,
59    infer: bool,
60    unsafety_isolation: usize,
61    alias: bool,
62    callgraph: bool,
63    api_dep: bool,
64    show_mir: bool,
65    dataflow: usize,
66    opt: usize,
67    heap_item: bool,
68    ssa: bool,
69    range: bool,
70}
71
72#[allow(clippy::derivable_impls)]
73impl Default for RapCallback {
74    fn default() -> Self {
75        Self {
76            rcanary: false,
77            safedrop: false,
78            verify: false,
79            infer: false,
80            unsafety_isolation: 0,
81            alias: false,
82            callgraph: false,
83            api_dep: false,
84            show_mir: false,
85            dataflow: 0,
86            opt: usize::MAX,
87            heap_item: false,
88            ssa: false,
89            range: false,
90        }
91    }
92}
93
94impl Callbacks for RapCallback {
95    fn config(&mut self, config: &mut Config) {
96        config.override_queries = Some(|_, providers| {
97            providers.extern_queries.used_crate_source = |tcx, cnum| {
98                let mut providers = Providers::default();
99                rustc_metadata::provide(&mut providers);
100                let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
101                // HACK: rustc will emit "crate ... required to be available in rlib format, but
102                // was not found in this form" errors once we use `tcx.dependency_formats()` if
103                // there's no rlib provided, so setting a dummy path here to workaround those errors.
104                Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
105                crate_source
106            };
107        });
108    }
109
110    fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
111        rap_trace!("Execute after_analysis() of compiler callbacks");
112        start_analyzer(tcx, *self);
113        rap_trace!("analysis done");
114        Compilation::Continue
115    }
116}
117
118impl RapCallback {
119    pub fn enable_rcanary(&mut self) {
120        self.rcanary = true;
121    }
122
123    pub fn is_rcanary_enabled(&self) -> bool {
124        self.rcanary
125    }
126
127    pub fn enable_alias(&mut self, arg: String) {
128        self.alias = true;
129        match arg.as_str() {
130            "-alias" => {
131                env::set_var("ALIAS", "1");
132            }
133            "-alias0" => {
134                env::set_var("ALIAS", "0");
135            }
136            "-alias1" => {
137                env::set_var("ALIAS", "1");
138            }
139            "-alias2" => {
140                env::set_var("ALIAS", "2");
141            }
142            _ => {}
143        }
144    }
145
146    pub fn is_alias_enabled(&self) -> bool {
147        self.alias
148    }
149
150    pub fn enable_safedrop(&mut self, arg: String) {
151        self.safedrop = true;
152        match arg.as_str() {
153            "-F" => {
154                env::set_var("SAFEDROP", "1");
155                env::set_var("MOP", "1");
156            }
157            "-F0" => {
158                env::set_var("SAFEDROP", "0");
159                env::set_var("MOP", "0");
160            }
161            "-F1" => {
162                env::set_var("SAFEDROP", "1");
163                env::set_var("MOP", "1");
164            }
165            "-F2" => {
166                env::set_var("SAFEDROP", "2");
167                env::set_var("MOP", "2");
168            }
169            "-uaf" => {
170                env::set_var("SAFEDROP", "1");
171                env::set_var("MOP", "1");
172            }
173            _ => {}
174        }
175    }
176
177    pub fn is_safedrop_enabled(&self) -> bool {
178        self.safedrop
179    }
180
181    pub fn enable_unsafety_isolation(&mut self, x: usize) {
182        self.unsafety_isolation = x;
183    }
184
185    pub fn is_unsafety_isolation_enabled(&self) -> usize {
186        self.unsafety_isolation
187    }
188
189    pub fn enable_api_dep(&mut self) {
190        self.api_dep = true;
191    }
192
193    pub fn is_api_dep_enabled(self) -> bool {
194        self.api_dep
195    }
196
197    pub fn enable_verify(&mut self) {
198        self.verify = true;
199    }
200
201    pub fn is_verify_enabled(&self) -> bool {
202        self.verify
203    }
204
205    pub fn enable_infer(&mut self) {
206        self.infer = true;
207    }
208
209    pub fn is_infer_enabled(&self) -> bool {
210        self.infer
211    }
212
213    pub fn enable_callgraph(&mut self) {
214        self.callgraph = true;
215    }
216
217    pub fn is_callgraph_enabled(&self) -> bool {
218        self.callgraph
219    }
220
221    pub fn enable_show_mir(&mut self) {
222        self.show_mir = true;
223    }
224
225    pub fn is_show_mir_enabled(&self) -> bool {
226        self.show_mir
227    }
228
229    pub fn enable_dataflow(&mut self, x: usize) {
230        self.dataflow = x;
231    }
232
233    pub fn is_dataflow_enabled(self) -> usize {
234        self.dataflow
235    }
236
237    pub fn enable_opt(&mut self, x: usize) {
238        self.opt = x;
239    }
240
241    pub fn is_opt_enabled(self) -> usize {
242        self.opt
243    }
244
245    pub fn enable_heap_item(&mut self) {
246        self.heap_item = true;
247    }
248
249    pub fn is_heap_item_enabled(self) -> bool {
250        self.heap_item
251    }
252    pub fn enable_ssa_transform(&mut self) {
253        self.ssa = true;
254    }
255    pub fn is_ssa_transform_enabled(self) -> bool {
256        self.ssa
257    }
258    pub fn enable_range_analysis(&mut self) {
259        self.range = true;
260    }
261    pub fn is_range_analysis_enabled(self) -> bool {
262        self.range
263    }
264}
265
266#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
267pub enum RapPhase {
268    Cleanup,
269    Cargo,
270    Rustc,
271    LLVM, // unimplemented yet
272}
273
274pub fn start_analyzer(tcx: TyCtxt, callback: RapCallback) {
275    let _rcanary: Option<rCanary> = if callback.is_rcanary_enabled() {
276        let mut heap = DefaultHeapAnalysis::new(tcx);
277        heap.run();
278        let adt_owner = heap.get_all_items();
279        let mut rcx = rCanary::new(tcx, adt_owner);
280        rcx.start();
281        Some(rcx)
282    } else {
283        None
284    };
285
286    if callback.is_alias_enabled() {
287        let mut alias = DefaultAlias::new(tcx);
288        alias.run();
289    }
290
291    if callback.is_safedrop_enabled() {
292        SafeDrop::new(tcx).start();
293    }
294
295    if callback.is_heap_item_enabled() {
296        let mut heap_analysis = DefaultHeapAnalysis::new(tcx);
297        heap_analysis.run();
298        heap_analysis.output();
299    }
300
301    let x = callback.is_unsafety_isolation_enabled();
302    match x {
303        1 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::StdSp),
304        2 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Doc),
305        3 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Upg),
306        4 => UnsafetyIsolationCheck::new(tcx).start(UigInstruction::Ucons),
307        _ => {}
308    }
309
310    if callback.is_verify_enabled() {
311        let check_level = CheckLevel::Medium;
312        SenryxCheck::new(tcx, 2).start(check_level, true);
313    }
314
315    if callback.is_infer_enabled() {
316        let check_level = CheckLevel::Medium;
317        SenryxCheck::new(tcx, 2).start(check_level, false);
318    }
319
320    if callback.is_show_mir_enabled() {
321        ShowMir::new(tcx).start();
322    }
323
324    if callback.is_api_dep_enabled() {
325        ApiDep::new(tcx).start();
326    }
327
328    match callback.is_dataflow_enabled() {
329        1 => DataFlow::new(tcx, false).start(),
330        2 => DataFlow::new(tcx, true).start(),
331        _ => {}
332    }
333
334    if callback.is_callgraph_enabled() {
335        CallGraph::new(tcx).start();
336    }
337
338    match callback.is_opt_enabled() {
339        0 => Opt::new(tcx, 0).start(),
340        1 => Opt::new(tcx, 1).start(),
341        2 => Opt::new(tcx, 2).start(),
342        _ => {}
343    }
344    if callback.is_ssa_transform_enabled() {
345        SSATrans::new(tcx, false).start();
346    }
347    if callback.is_range_analysis_enabled() {
348        let mut analyzer = DefaultRange::<i32>::new(tcx, false);
349        analyzer.run();
350    }
351}