1#![feature(rustc_private)]
2
3#[macro_use]
4pub mod utils;
5pub mod analysis;
6pub mod check;
7pub mod cli;
8pub(crate) mod compat;
9pub(crate) mod def_id;
10pub(crate) mod graphs;
11pub mod help;
12pub(crate) mod helpers;
13pub(crate) mod preprocess;
14pub mod verify;
15
16extern crate rustc_abi;
17extern crate rustc_ast;
18extern crate rustc_data_structures;
19extern crate rustc_driver;
20
21extern crate rustc_hir;
22extern crate rustc_hir_pretty;
23extern crate rustc_index;
24extern crate rustc_infer;
25extern crate rustc_interface;
26extern crate rustc_metadata;
27extern crate rustc_middle;
28extern crate rustc_mir_dataflow;
29extern crate rustc_public;
30extern crate rustc_session;
31extern crate rustc_span;
32
33extern crate rustc_trait_selection;
34
35extern crate rustc_type_ir;
36extern crate thin_vec;
37
38use crate::{
39 analysis::{alias::mfp::MfpAliasAnalyzer, api_dependency, scan::ScanAnalysis},
40 check::{opt::Opt, rcanary::rCanary, safedrop::SafeDrop},
41 cli::{
42 AliasStrategyKind, AnalysisKind, CheckArgs, Commands, PostfixRepeat, RapxArgs, VerifyArgs,
43 },
44 verify::{driver::VerifyRun, loop_sensitivity::RepeatStrategy, target::PrepareTargets},
45};
46use analysis::{
47 Analysis,
48 alias::{AliasAnalysis, FnAliasMapWrapper, default::AliasAnalyzer},
49 api_dependency::ApiDependencyAnalyzer,
50 callgraph::{CallGraphAnalysis, FnCallDisplay, default::CallGraphAnalyzer},
51 dataflow::{Arg2RetMapWrapper, DataflowAnalysis, default::DataflowAnalyzer},
52 owned_heap::{OHAResultMapWrapper, OwnedHeapAnalysis, default::OwnedHeapAnalyzer},
53 path::{PathMapWrapper, default::PathAnalyzer},
54 range::{
55 PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis, default::RangeAnalyzer,
56 },
57 safety_flow::{SafetyFlowAnalysis, TargetCrate},
58 ssa_transform::SSATrans,
59};
60use helpers::show_mir::ShowMir;
61use rustc_ast::ast;
62use rustc_driver::{Callbacks, Compilation};
63use rustc_interface::interface::{self, Compiler};
64use rustc_middle::{ty::TyCtxt, util::Providers};
65#[cfg(not(rapx_ge_99))]
66use rustc_session::search_paths::PathKind;
67use std::path::PathBuf;
68use std::sync::Arc;
69
70pub static RAPX_DEFAULT_ARGS: &[&str] = &[
71 "-Zalways-encode-mir",
72 "-Zmir-opt-level=0",
73 "-Zinline-mir-threshold=0",
74 "-Zinline-mir-hint-threshold=0",
75 "-Zcross-crate-inline-threshold=0",
76];
77
78#[derive(Debug, Clone)]
81pub struct RapCallback {
82 args: RapxArgs,
83}
84
85impl RapCallback {
86 pub fn new(args: RapxArgs) -> Self {
87 Self { args }
88 }
89
90 fn is_building_test_crate(&self) -> bool {
91 match &self.args.test_crate {
92 None => true,
93 Some(test_crate) => {
94 let test_crate: &str = test_crate;
95 let package_name = std::env::var("CARGO_PKG_NAME")
96 .expect("cannot capture env var `CARGO_PKG_NAME`");
97 package_name == test_crate
98 }
99 }
100 }
101}
102
103impl Callbacks for RapCallback {
104 fn config(&mut self, config: &mut rustc_interface::Config) {
105 config.override_queries = Some(|_, providers| {
106 providers.extern_queries.used_crate_source = |tcx, cnum| {
107 let mut providers = Providers::default();
108 rustc_metadata::provide(&mut providers);
109 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
110 #[cfg(rapx_ge_99)]
114 {
115 Arc::make_mut(&mut crate_source).rlib = Some(PathBuf::new());
116 }
117 #[cfg(not(rapx_ge_99))]
118 {
119 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
120 }
121 crate_source
122 };
123 });
124 }
125
126 fn after_crate_root_parsing(
127 &mut self,
128 compiler: &interface::Compiler,
129 krate: &mut ast::Crate,
130 ) -> Compilation {
131 let build_std = compiler
132 .sess
133 .opts
134 .crate_name
135 .as_deref()
136 .map(|s| matches!(s, "core" | "std" | "alloc" | "proc_macro" | "test"))
137 .unwrap_or(false);
138 preprocess::dummy_fns::create_dummy_fns(krate, build_std);
139 preprocess::ssa_preprocess::create_ssa_struct(krate, build_std);
140 Compilation::Continue
141 }
142 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
143 rap_trace!("Execute after_analysis() of compiler callbacks");
144 rustc_public::rustc_internal::run(tcx, || {
145 def_id::init(tcx);
146 if self.is_building_test_crate() {
147 start_analyzer(tcx, self);
148 } else {
149 let package_name = std::env::var("CARGO_PKG_NAME")
150 .expect("cannot capture env var `CARGO_PKG_NAME`");
151 rap_trace!("skip analyzing package `{}`", package_name);
152 }
153 })
154 .expect("Failed to run rustc_public.");
155
156 rap_trace!("analysis done");
157 Compilation::Continue
158 }
159}
160
161pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
163 match &callback.args.command {
164 Commands::Check(CheckArgs { uaf, mleak }) => {
165 if uaf.is_some() {
166 SafeDrop::new(tcx).start();
167 }
168 if *mleak {
169 let mut heap = OwnedHeapAnalyzer::new(tcx);
170 heap.run();
171 let adt_owner = heap.get_all_items();
172 rCanary::new(tcx, adt_owner).start();
173 }
174 }
175
176 Commands::Opt => {
177 Opt::new(tcx, 1).start();
178 }
179
180 Commands::Analyze { kind } => match kind {
181 AnalysisKind::Alias { strategy } => {
182 let alias = match strategy {
183 AliasStrategyKind::Mop => {
184 let mut analyzer = AliasAnalyzer::new(tcx);
185 analyzer.run();
186 analyzer.get_local_fn_alias()
187 }
188 AliasStrategyKind::Mfp => {
189 let mut analyzer = MfpAliasAnalyzer::new(tcx);
190 analyzer.run();
191 analyzer.get_local_fn_alias()
192 }
193 };
194 rap_info!("{}", FnAliasMapWrapper(alias));
195 }
196 AnalysisKind::Adg(args) => {
197 let config = api_dependency::Config {
198 resolve_generic: true,
199 visit_config: api_dependency::VisitConfig {
200 pub_only: !args.include_private,
201 include_generic: true,
202 ignore_const_generic: true,
203 include_unsafe: args.include_unsafe,
204 include_drop: args.include_drop,
205 },
206 max_generic_search_iteration: args.max_iteration,
207 dump: args.dump.clone(),
208 };
209 let mut analyzer = ApiDependencyAnalyzer::new(tcx, config);
210 analyzer.run();
211 }
212 &AnalysisKind::SafetyFlow { draw } => {
213 SafetyFlowAnalysis::new(tcx)
214 .with_draw(draw)
215 .start(TargetCrate::Other);
216 }
217 &AnalysisKind::SafetyFlowStd { draw } => {
218 SafetyFlowAnalysis::new(tcx)
219 .with_draw(draw)
220 .start(TargetCrate::Std);
221 }
222 AnalysisKind::Callgraph => {
223 let mut analyzer = CallGraphAnalyzer::new(tcx);
224 analyzer.run();
225 let callgraph = analyzer.get_fn_calls();
226 rap_info!(
227 "{}",
228 FnCallDisplay {
229 fn_calls: &callgraph,
230 tcx
231 }
232 );
233 }
234 &AnalysisKind::Dataflow { debug, draw } => {
235 let mut analyzer = DataflowAnalyzer::new(tcx, debug).with_draw(draw);
236 analyzer.run();
237 let result = analyzer.get_all_arg2ret();
238 rap_info!("{}", Arg2RetMapWrapper(result));
239 }
240 AnalysisKind::OwnedHeap => {
241 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
242 analyzer.run();
243 let result = analyzer.get_all_items();
244 rap_info!("{}", OHAResultMapWrapper(result));
245 }
246 &AnalysisKind::Paths { postfix_repeat } => {
247 let mut analyzer = PathAnalyzer::new(tcx, false);
248 analyzer.run_with_repeat(postfix_repeat);
249 let result = analyzer.get_all_paths();
250 rap_info!("{}", PathMapWrapper(result, &analyzer.graphs));
251 }
252 AnalysisKind::Pathcond => {
253 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
254 analyzer.start_path_constraints_analysis();
255 let result = analyzer.get_all_path_constraints();
256 rap_info!("{}", PathConstraintMapWrapper(result));
257 }
258 &AnalysisKind::Range { debug } => {
259 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, debug);
260 analyzer.run();
261 let result = analyzer.get_all_fn_ranges();
262 rap_info!("{}", RAResultMapWrapper(result));
263 }
264
265 AnalysisKind::Scan => {
266 ScanAnalysis::new(tcx).run();
267 }
268 AnalysisKind::Mir => {
269 ShowMir::new(tcx).start();
270 }
271 AnalysisKind::DotMir => {
272 ShowMir::new(tcx).start_generate_dot();
273 }
274 AnalysisKind::Ssa => {
275 SSATrans::new(tcx, false).start();
276 }
277 },
278
279 Commands::Verify(VerifyArgs {
280 prepare_targets,
281 postfix_repeat,
282 mode,
283 skip_invariant,
284 crate_name,
285 module,
286 debug_contracts,
287 ..
288 }) => {
289 if *prepare_targets {
290 PrepareTargets::new(
291 tcx,
292 *mode,
293 *skip_invariant,
294 crate_name.clone(),
295 module.clone(),
296 )
297 .run();
298 } else {
299 let repeat_strategy = match postfix_repeat {
300 PostfixRepeat::Auto => RepeatStrategy::Auto,
301 PostfixRepeat::Fixed(n) => RepeatStrategy::Fixed(*n),
302 };
303 VerifyRun::new(
304 tcx,
305 repeat_strategy,
306 *mode,
307 *skip_invariant,
308 crate_name.clone(),
309 module.clone(),
310 *debug_contracts,
311 )
312 .run();
313 }
314 }
315 }
316}