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