flowistry_ifc/
lib.rs

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}