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 check;
9pub mod cli;
10pub mod def_id;
11pub mod help;
12pub mod preprocess;
13pub mod verify;
14
15extern crate rustc_abi;
16extern crate rustc_ast;
17extern crate rustc_data_structures;
18extern crate rustc_driver;
19extern crate rustc_errors;
20extern crate rustc_hir;
21extern crate rustc_hir_pretty;
22extern crate rustc_index;
23extern crate rustc_infer;
24extern crate rustc_interface;
25extern crate rustc_metadata;
26extern crate rustc_middle;
27extern crate rustc_mir_dataflow;
28extern crate rustc_public;
29extern crate rustc_session;
30extern crate rustc_span;
31extern crate rustc_target;
32extern crate rustc_trait_selection;
33extern crate rustc_traits;
34extern crate rustc_type_ir;
35extern crate thin_vec;
36
37use crate::{
38 analysis::{
39 core::{alias_analysis::mfp::MfpAliasAnalyzer, api_dependency},
40 scan::ScanAnalysis,
41 },
42 check::{
43 opt::Opt,
44 rcanary::rCanary,
45 safedrop::SafeDrop,
46 senryx::{CheckLevel, SenryxCheck},
47 },
48 cli::{AliasStrategyKind, AnalysisKind, CheckArgs, Commands, OptLevel, RapxArgs, VerifyArgs},
49 verify::target::PrepareTargets,
50};
51use analysis::{
52 Analysis,
53 core::{
54 alias_analysis::{AliasAnalysis, FnAliasMapWrapper, default::AliasAnalyzer},
55 api_dependency::ApiDependencyAnalyzer,
56 callgraph::{CallGraphAnalysis, FnCallDisplay, default::CallGraphAnalyzer},
57 dataflow::{
58 Arg2RetMapWrapper, DataFlowAnalysis, DataFlowGraphMapWrapper, default::DataFlowAnalyzer,
59 },
60 ownedheap_analysis::{OHAResultMapWrapper, OwnedHeapAnalysis, default::OwnedHeapAnalyzer},
61 range_analysis::{
62 PathConstraintMapWrapper, RAResultMapWrapper, RangeAnalysis, default::RangeAnalyzer,
63 },
64 ssa_transform::SSATrans,
65 },
66 upg::{TargetCrate, UPGAnalysis},
67 utils::show_mir::ShowMir,
68};
69use rustc_ast::ast;
70use rustc_driver::{Callbacks, Compilation};
71use rustc_interface::interface::{self, Compiler};
72use rustc_middle::{ty::TyCtxt, util::Providers};
73use rustc_session::search_paths::PathKind;
74use std::path::PathBuf;
75use std::sync::Arc;
76
77pub static RAP_DEFAULT_ARGS: &[&str] = &[
78 "-Zalways-encode-mir",
79 "-Zmir-opt-level=0",
80 "-Zinline-mir-threshold=0",
81 "-Zinline-mir-hint-threshold=0",
82 "-Zcross-crate-inline-threshold=0",
83];
84
85#[derive(Debug, Clone)]
88pub struct RapCallback {
89 args: RapxArgs,
90}
91
92impl RapCallback {
93 pub fn new(args: RapxArgs) -> Self {
94 Self { args }
95 }
96
97 fn is_building_test_crate(&self) -> bool {
98 match &self.args.test_crate {
99 None => true,
100 Some(test_crate) => {
101 let test_crate: &str = test_crate;
102 let package_name = std::env::var("CARGO_PKG_NAME")
103 .expect("cannot capture env var `CARGO_PKG_NAME`");
104 package_name == test_crate
105 }
106 }
107 }
108}
109
110impl Callbacks for RapCallback {
111 fn config(&mut self, config: &mut rustc_interface::Config) {
112 config.override_queries = Some(|_, providers| {
113 providers.extern_queries.used_crate_source = |tcx, cnum| {
114 let mut providers = Providers::default();
115 rustc_metadata::provide(&mut providers);
116 let mut crate_source = (providers.extern_queries.used_crate_source)(tcx, cnum);
117 Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
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"))
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 {
165 uaf,
166 mleak,
167 opt,
168 infer,
169 verify,
170 verify_std,
171 }) => {
172 if uaf.is_some() {
173 SafeDrop::new(tcx).start();
174 }
175 if *mleak {
176 let mut heap = OwnedHeapAnalyzer::new(tcx);
177 heap.run();
178 let adt_owner = heap.get_all_items();
179 rCanary::new(tcx, adt_owner).start();
180 }
181 if let Some(opt_level) = opt {
182 match opt_level {
183 OptLevel::Report => Opt::new(tcx, 0).start(),
184 OptLevel::Default => Opt::new(tcx, 1).start(),
185 OptLevel::All => Opt::new(tcx, 2).start(),
186 }
187 }
188 if *infer {
189 let check_level = CheckLevel::Medium;
190 SenryxCheck::new(tcx, 2).start(check_level, false);
191 }
192 if *verify {
193 let check_level = CheckLevel::Medium;
194 SenryxCheck::new(tcx, 2).start(check_level, true);
195 }
196
197 if *verify_std {
198 SenryxCheck::new(tcx, 2).start_analyze_std_func();
199 }
201 }
202
203 Commands::Analyze { kind } => match kind {
204 AnalysisKind::Alias { strategy } => {
205 let alias = match strategy {
206 AliasStrategyKind::Mop => {
207 let mut analyzer = AliasAnalyzer::new(tcx);
208 analyzer.run();
209 analyzer.get_local_fn_alias()
210 }
211 AliasStrategyKind::Mfp => {
212 let mut analyzer = MfpAliasAnalyzer::new(tcx);
213 analyzer.run();
214 analyzer.get_local_fn_alias()
215 }
216 };
217 rap_info!("{}", FnAliasMapWrapper(alias));
218 }
219 AnalysisKind::Adg(args) => {
220 let config = api_dependency::Config {
221 resolve_generic: true,
222 visit_config: api_dependency::VisitConfig {
223 pub_only: !args.include_private,
224 include_generic: true,
225 ignore_const_generic: true,
226 include_unsafe: args.include_unsafe,
227 include_drop: args.include_drop,
228 },
229 max_generic_search_iteration: args.max_iteration,
230 dump: args.dump.clone(),
231 };
232 let mut analyzer = ApiDependencyAnalyzer::new(tcx, config);
233 analyzer.run();
234 }
235 AnalysisKind::Upg => {
236 UPGAnalysis::new(tcx).start(TargetCrate::Other);
237 }
238 AnalysisKind::UpgStd => {
239 UPGAnalysis::new(tcx).start(TargetCrate::Std);
240 }
241 AnalysisKind::Callgraph => {
242 let mut analyzer = CallGraphAnalyzer::new(tcx);
243 analyzer.run();
244 let callgraph = analyzer.get_fn_calls();
245 rap_info!(
246 "{}",
247 FnCallDisplay {
248 fn_calls: &callgraph,
249 tcx
250 }
251 );
252 }
253 &AnalysisKind::Dataflow { debug } => {
254 if debug {
255 let mut analyzer = DataFlowAnalyzer::new(tcx, true);
256 analyzer.run();
257 let result = analyzer.get_all_dataflow();
258 rap_info!("{}", DataFlowGraphMapWrapper(result));
259 } else {
260 let mut analyzer = DataFlowAnalyzer::new(tcx, false);
261 analyzer.run();
262 let result = analyzer.get_all_arg2ret();
263 rap_info!("{}", Arg2RetMapWrapper(result));
264 }
265 }
266 AnalysisKind::OwnedHeap => {
267 let mut analyzer = OwnedHeapAnalyzer::new(tcx);
268 analyzer.run();
269 let result = analyzer.get_all_items();
270 rap_info!("{}", OHAResultMapWrapper(result));
271 }
272 AnalysisKind::Pathcond => {
273 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, false);
274 analyzer.start_path_constraints_analysis();
275 let result = analyzer.get_all_path_constraints();
276 rap_info!("{}", PathConstraintMapWrapper(result));
277 }
278 &AnalysisKind::Range { debug } => {
279 let mut analyzer = RangeAnalyzer::<i64>::new(tcx, debug);
280 analyzer.run();
281 let result = analyzer.get_all_fn_ranges();
282 rap_info!("{}", RAResultMapWrapper(result));
283 }
284
285 AnalysisKind::Scan => {
286 ScanAnalysis::new(tcx).run();
287 }
288 AnalysisKind::Mir => {
289 ShowMir::new(tcx).start();
290 }
291 AnalysisKind::DotMir => {
292 ShowMir::new(tcx).start_generate_dot();
293 }
294 AnalysisKind::Ssa => {
295 SSATrans::new(tcx, false).start();
296 }
297 },
298
299 Commands::Verify(VerifyArgs { prepare_targets }) => {
300 if *prepare_targets {
301 PrepareTargets::new(tcx).run();
302 }
303 }
304 }
305}