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
58pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
61
62#[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 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 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 pub fn is_alias_enabled(&self) -> bool {
165 self.alias
166 }
167
168 pub fn enable_api_dependency(&mut self) {
170 self.api_dependency = true;
171 }
172
173 pub fn is_api_dependency_enabled(self) -> bool {
175 self.api_dependency
176 }
177
178 pub fn enable_callgraph(&mut self) {
180 self.callgraph = true;
181 }
182
183 pub fn is_callgraph_enabled(&self) -> bool {
185 self.callgraph
186 }
187
188 pub fn enable_ownedheap(&mut self) {
190 self.ownedheap = true;
191 }
192
193 pub fn is_ownedheap_enabled(self) -> bool {
195 self.ownedheap
196 }
197
198 pub fn enable_dataflow(&mut self, x: usize) {
200 self.dataflow = x;
201 }
202
203 pub fn is_dataflow_enabled(self) -> usize {
205 self.dataflow
206 }
207
208 pub fn enable_range_analysis(&mut self, x: usize) {
210 self.range = x;
211 }
212
213 pub fn is_range_analysis_enabled(self) -> bool {
215 self.range > 0
216 }
217
218 pub fn enable_test(&mut self) {
220 self.test = true;
221 }
222
223 pub fn is_test_enabled(self) -> bool {
225 self.test
226 }
227
228 pub fn enable_ssa_transform(&mut self) {
230 self.ssa = true;
231 }
232
233 pub fn is_ssa_transform_enabled(self) -> bool {
235 self.ssa
236 }
237
238 pub fn enable_opt(&mut self, x: usize) {
240 self.opt = x;
241 }
242
243 pub fn is_opt_enabled(self) -> usize {
245 self.opt
246 }
247
248 pub fn enable_rcanary(&mut self) {
250 self.rcanary = true;
251 }
252
253 pub fn is_rcanary_enabled(&self) -> bool {
255 self.rcanary
256 }
257
258 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 pub fn is_safedrop_enabled(&self) -> bool {
290 self.safedrop
291 }
292
293 pub fn enable_show_mir(&mut self) {
295 self.show_mir = true;
296 }
297
298 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
328pub 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 }
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}