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
61pub static RAP_DEFAULT_ARGS: &[&str] = &["-Zalways-encode-mir", "-Zmir-opt-level=0"];
64
65#[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 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 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 pub fn is_alias_enabled(&self) -> bool {
173 self.alias
174 }
175
176 pub fn enable_api_dependency(&mut self) {
178 self.api_dependency = true;
179 }
180
181 pub fn is_api_dependency_enabled(&self) -> bool {
183 self.api_dependency
184 }
185
186 pub fn enable_callgraph(&mut self) {
188 self.callgraph = true;
189 }
190
191 pub fn is_callgraph_enabled(&self) -> bool {
193 self.callgraph
194 }
195
196 pub fn enable_ownedheap(&mut self) {
198 self.ownedheap = true;
199 }
200
201 pub fn is_ownedheap_enabled(&self) -> bool {
203 self.ownedheap
204 }
205
206 pub fn enable_dataflow(&mut self, x: usize) {
208 self.dataflow = x;
209 }
210
211 pub fn is_dataflow_enabled(&self) -> usize {
213 self.dataflow
214 }
215
216 pub fn enable_range_analysis(&mut self, x: usize) {
218 self.range = x;
219 }
220
221 pub fn is_range_analysis_enabled(&self) -> bool {
223 self.range > 0
224 }
225
226 pub fn enable_test(&mut self) {
228 self.test = true;
229 }
230
231 pub fn is_test_enabled(&self) -> bool {
233 self.test
234 }
235
236 pub fn enable_ssa_transform(&mut self) {
238 self.ssa = true;
239 }
240
241 pub fn is_ssa_transform_enabled(&self) -> bool {
243 self.ssa
244 }
245
246 pub fn enable_opt(&mut self, x: usize) {
248 self.opt = x;
249 }
250
251 pub fn is_opt_enabled(&self) -> usize {
253 self.opt
254 }
255
256 pub fn enable_rcanary(&mut self) {
258 self.rcanary = true;
259 }
260
261 pub fn is_rcanary_enabled(&self) -> bool {
263 self.rcanary
264 }
265
266 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 pub fn is_safedrop_enabled(&self) -> bool {
298 self.safedrop
299 }
300
301 pub fn enable_show_mir(&mut self) {
303 self.show_mir = true;
304 }
305
306 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
344pub 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 }
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}