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