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