1#![feature(rustc_private)]
2
3extern crate rustc_data_structures;
4extern crate rustc_driver;
5extern crate rustc_hir;
6extern crate rustc_infer;
7extern crate rustc_interface;
8extern crate rustc_middle;
9extern crate rustc_mir_dataflow;
10extern crate rustc_span;
11extern crate rustc_trait_selection;
12extern crate rustc_traits;
13
14mod analysis;
15
16use std::{borrow::Cow, io::Write};
17
18use analysis::IssueFound;
19use flowistry::infoflow;
20use rustc_hir::{
21 BodyId,
22 intravisit::{self, Visitor},
23};
24use rustc_middle::{hir::nested_filter::OnlyBodies, ty::TyCtxt};
25use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs};
26use rustc_utils::mir::borrowck_facts;
27use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
28pub struct IfcPlugin;
29
30impl RustcPlugin for IfcPlugin {
31 type Args = ();
32
33 fn driver_name(&self) -> Cow<'static, str> {
34 "ifc-driver".into()
35 }
36
37 fn version(&self) -> Cow<'static, str> {
38 env!("CARGO_PKG_VERSION").into()
39 }
40
41 fn args(&self, _target_dir: &rustc_plugin::Utf8Path) -> RustcPluginArgs<Self::Args> {
42 RustcPluginArgs {
43 args: (),
44 filter: CrateFilter::OnlyWorkspace,
45 }
46 }
47
48 fn run(
49 self,
50 compiler_args: Vec<String>,
51 _plugin_args: Self::Args,
52 ) -> rustc_interface::interface::Result<()> {
53 rustc_driver::run_compiler(&compiler_args, &mut Callbacks);
54 Ok(())
55 }
56}
57
58pub struct IfcVisitor<'tcx> {
59 tcx: TyCtxt<'tcx>,
60 issue_found: IssueFound,
61}
62
63impl<'tcx> Visitor<'tcx> for IfcVisitor<'tcx> {
64 type NestedFilter = OnlyBodies;
65
66 fn visit_nested_body(&mut self, body_id: BodyId) {
67 intravisit::walk_body(self, self.tcx.hir_body(body_id));
68
69 let tcx = self.tcx;
70 let local_def_id = tcx.hir_body_owner_def_id(body_id);
71 let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, local_def_id);
72 let flow = &infoflow::compute_flow(tcx, body_id, body_with_facts);
73 if let IssueFound::Yes = analysis::analyze(&body_id, flow).unwrap() {
74 self.issue_found = IssueFound::Yes;
75 }
76 }
77}
78
79pub struct Callbacks;
80impl rustc_driver::Callbacks for Callbacks {
81 fn config(&mut self, config: &mut rustc_interface::Config) {
82 borrowck_facts::enable_mir_simplification();
83 config.override_queries = Some(borrowck_facts::override_queries);
84 }
85
86 fn after_analysis(
87 &mut self,
88 _compiler: &rustc_interface::interface::Compiler,
89 tcx: TyCtxt,
90 ) -> rustc_driver::Compilation {
91 let mut visitor = IfcVisitor {
92 tcx,
93 issue_found: IssueFound::No,
94 };
95 tcx.hir_visit_all_item_likes_in_crate(&mut visitor);
96
97 if let IssueFound::No = visitor.issue_found {
98 let mut stdout = StandardStream::stderr(ColorChoice::Auto);
99 let mut green_spec = ColorSpec::new();
100 green_spec.set_fg(Some(Color::Green));
101 stdout.set_color(&green_spec).unwrap();
102 writeln!(stdout, "No security issues found!",).unwrap();
103 }
104
105 rustc_driver::Compilation::Stop
106 }
107}