rapx/check/opt/checking/bounds_checking/
bounds_extend.rs1use 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}