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(crate) mod limit;
12pub mod help;
13pub(crate) mod helpers;
14pub(crate) mod preprocess;
15pub(crate) mod verify;
16
17extern crate rustc_abi;
18extern crate rustc_ast;
19#[cfg(rapx_has_attr_ir)]
20extern crate rustc_attr_ir;
21extern crate rustc_data_structures;
22extern crate rustc_driver;
23extern crate rustc_hir;
24extern crate rustc_hir_pretty;
25extern crate rustc_index;
26extern crate rustc_infer;
27extern crate rustc_interface;
28extern crate rustc_metadata;
29extern crate rustc_middle;
30extern crate rustc_mir_dataflow;
31extern crate rustc_public;
32extern crate rustc_session;
33extern crate rustc_span;
34extern crate rustc_trait_selection;
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 heap_ownership::{
53 HeapOwnershipAnalysis, HeapOwnershipResultMapWrapper, default::HeapOwnershipAnalyzer,
54 },
55 path::{PathMapWrapper, default::PathAnalyzer},
56 range::{PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis, default::RangeAnalyzer},
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_95))]
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_95)]
114 {
115 Arc::make_mut(&mut crate_source).rlib = Some(PathBuf::new());
116 }
117 #[cfg(not(rapx_ge_95))]
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
139 preprocess::dummy_fns::create_dummy_fns(krate, build_std);
140 preprocess::ssa_preprocess::create_ssa_struct(krate, build_std);
141 Compilation::Continue
142 }
143
144 fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
145 rap_trace!("Execute after_analysis() of compiler callbacks");
146 rustc_public::rustc_internal::run(tcx, || {
147 def_id::init(tcx);
148 if self.is_building_test_crate() {
149 start_analyzer(tcx, self);
150 } else {
151 let package_name = std::env::var("CARGO_PKG_NAME")
152 .expect("cannot capture env var `CARGO_PKG_NAME`");
153 rap_trace!("skip analyzing package `{}`", package_name);
154 }
155 })
156 .expect("Failed to run rustc_public.");
157
158 rap_trace!("analysis done");
159 Compilation::Continue
160 }
161}
162
163pub fn start_analyzer(tcx: TyCtxt, callback: &RapCallback) {
165 match &callback.args.command {
166 Commands::Check(CheckArgs { uaf, mleak }) => {
167 if uaf.is_some() {
168 SafeDrop::new(tcx).start();
169 }
170 if *mleak {
171 let mut heap = HeapOwnershipAnalyzer::new(tcx);
172 heap.run();
173 let adt_owner = heap.get_all_items();
174 rCanary::new(tcx, adt_owner).start();
175 }
176 }
177
178 Commands::Opt => {
179 Opt::new(tcx, 1).start();
180 }
181
182 Commands::Analyze { kind } => match kind {
183 AnalysisKind::Alias { strategy } => {
184 let alias = match strategy {
185 AliasStrategyKind::Mop => {
186 let mut analyzer = AliasAnalyzer::new(tcx);
187 analyzer.run();
188 analyzer.get_local_fn_alias()
189 }
190 AliasStrategyKind::Mfp => {
191 let mut analyzer = MfpAliasAnalyzer::new(tcx);
192 analyzer.run();
193 analyzer.get_local_fn_alias()
194 }
195 };
196 rap_info!("{}", FnAliasMapWrapper(alias));
197 }
198 AnalysisKind::Adg(args) => {
199 let config = api_dependency::Config {
200 resolve_generic: true,
201 visit_config: api_dependency::VisitConfig {
202 pub_only: !args.include_private,
203 include_generic: true,
204 ignore_const_generic: true,
205 include_unsafe: args.include_unsafe,
206 include_drop: args.include_drop,
207 },
208 max_generic_search_iteration: args.max_iteration,
209 dump: args.dump.clone(),
210 };
211 let mut analyzer = ApiDependencyAnalyzer::new(tcx, config);
212 analyzer.run();
213 }
214 &AnalysisKind::SafetyFlow { draw } => {
215 SafetyFlowAnalysis::new(tcx)
216 .with_draw(draw)
217 .start(TargetCrate::Other);
218 }
219 &AnalysisKind::SafetyFlowStd { draw } => {
220 SafetyFlowAnalysis::new(tcx)
221 .with_draw(draw)
222 .start(TargetCrate::Std);
223 }
224 AnalysisKind::Callgraph => {
225 let mut analyzer = CallGraphAnalyzer::new(tcx);
226 analyzer.run();
227 let callgraph = analyzer.get_fn_calls();
228 rap_info!(
229 "{}",
230 FnCallDisplay {
231 fn_calls: &callgraph,
232 tcx
233 }
234 );
235 }
236 &AnalysisKind::Dataflow { debug, draw } => {
237 let mut analyzer = DataflowAnalyzer::new(tcx, debug).with_draw(draw);
238 analyzer.run();
239 let result = analyzer.get_all_arg2ret();
240 rap_info!("{}", Arg2RetMapWrapper(result));
241 }
242 AnalysisKind::HeapOwnership => {
243 let mut analyzer = HeapOwnershipAnalyzer::new(tcx);
244 analyzer.run();
245 let result = analyzer.get_all_items();
246 rap_info!("{}", HeapOwnershipResultMapWrapper(result));
247 }
248 &AnalysisKind::Paths { postfix_repeat } => {
249 let mut analyzer = PathAnalyzer::new(tcx, false);
250 analyzer.run_with_repeat(postfix_repeat);
251 let result = analyzer.get_all_paths();
252 rap_info!("{}", PathMapWrapper(result, &analyzer.graphs));
253 }
254 AnalysisKind::Pathcond => {
255 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
256 analyzer.start_path_constraints_analysis();
257 let result = analyzer.get_all_path_constraints();
258 rap_info!("{}", PathConstraintMapWrapper(result));
259 }
260 &AnalysisKind::Range { debug } => {
261 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, debug);
262 analyzer.run();
263 let result = analyzer.get_all_fn_ranges();
264 rap_info!("{}", RAResultMapWrapper(result));
265 }
266
267 AnalysisKind::Scan => {
268 ScanAnalysis::new(tcx).run();
269 }
270 AnalysisKind::Mir => {
271 ShowMir::new(tcx).start();
272 }
273 AnalysisKind::DotMir => {
274 ShowMir::new(tcx).start_generate_dot();
275 }
276 AnalysisKind::Ssa => {
277 SSATrans::new(tcx, false).start();
278 }
279 },
280
281 Commands::Verify(VerifyArgs {
282 prepare_targets,
283 postfix_repeat,
284 mode,
285 skip_invariant,
286 crate_name,
287 module,
288 debug_contracts,
289 path_limit,
290 ..
291 }) => {
292 if let Some(n) = path_limit {
293 crate::limit::set_path_limit(*n);
294 }
295 if *prepare_targets {
296 PrepareTargets::new(
297 tcx,
298 *mode,
299 *skip_invariant,
300 crate_name.clone(),
301 module.clone(),
302 )
303 .run();
304 } else {
305 let repeat_strategy = match postfix_repeat {
306 PostfixRepeat::Auto => RepeatStrategy::Auto,
307 PostfixRepeat::Fixed(n) => RepeatStrategy::Fixed(*n),
308 };
309 VerifyRun::new(
310 tcx,
311 repeat_strategy,
312 *mode,
313 *skip_invariant,
314 crate_name.clone(),
315 module.clone(),
316 *debug_contracts,
317 )
318 .run();
319 }
320 }
321 }
322}