Skip to main content

rapx/check/opt/checking/bounds_checking/
bounds_extend.rs

1use once_cell::sync::OnceCell;
2
3use rustc_middle::ty::TyCtxt;
4use rustc_span::Span;
5
6use crate::{
7    analysis::dataflow::*,
8    helpers::def_path::DefPath,
9};
10use annotate_snippets::Level;
11
12use crate::check::opt::report::OptReport;
13use crate::check::opt::check_utils::node_matches_call;
14
15use super::super::super::LEVEL;
16use super::super::super::NO_STD;
17use crate::check::opt::OptCheck;
18static DEFPATHS: OnceCell<DefPaths> = OnceCell::new();
19
20struct DefPaths {
21    vec_extend_from_slice: DefPath,
22}
23
24impl DefPaths {
25    pub fn new(tcx: &TyCtxt<'_>) -> Self {
26        let no_std = NO_STD.lock().unwrap();
27        if *no_std {
28            Self {
29                vec_extend_from_slice: DefPath::new("alloc::vec::Vec::extend_from_slice", &tcx),
30            }
31        } else {
32            Self {
33                vec_extend_from_slice: DefPath::new("std::vec::Vec::extend_from_slice", &tcx),
34            }
35        }
36    }
37}
38
39pub struct BoundsExtendCheck {
40    pub record: Vec<Span>,
41}
42
43impl OptCheck for BoundsExtendCheck {
44    fn new() -> Self {
45        Self { record: Vec::new() }
46    }
47
48    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
49        let level = LEVEL.lock().unwrap();
50        if *level <= 1 {
51            return;
52        }
53        let def_paths = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
54        for node in graph.nodes.iter() {
55            if node_matches_call(node, &[def_paths.vec_extend_from_slice.last_def_id()]) {
56                self.record.push(node.span);
57            }
58        }
59    }
60
61    fn report(&self, graph: &Graph) {
62        for span in self.record.iter() {
63            report_extend_bug(graph, *span);
64        }
65    }
66
67    fn cnt(&self) -> usize {
68        self.record.len()
69    }
70}
71
72fn report_extend_bug(graph: &Graph, span: Span) {
73    OptReport::from_graph(graph)
74        .title("Unnecessary bound checkings detected")
75        .annotate(Level::Error, span, "Checked here.")
76        .footer("Manipulate memory directly.")
77        .emit();
78}