Skip to main content

rapx/check/opt/checking/
encoding_checking.rs

1pub mod array_encoding;
2pub mod string_lowercase;
3pub mod string_push;
4pub mod vec_encoding;
5
6use crate::{analysis::dataflow::*, check::opt::OptCheck};
7
8use annotate_snippets::Level;
9
10use crate::check::opt::report::OptReport;
11
12use rustc_middle::{mir::Local, ty::TyCtxt};
13use rustc_span::Span;
14
15use array_encoding::ArrayEncodingCheck;
16use string_lowercase::StringLowercaseCheck;
17use string_push::StringPushCheck;
18use vec_encoding::VecEncodingCheck;
19
20pub struct EncodingCheck {
21    vec_encoding: VecEncodingCheck,
22    array_encoding: ArrayEncodingCheck,
23    string_push: StringPushCheck,
24    string_lowercase: StringLowercaseCheck,
25}
26
27impl OptCheck for EncodingCheck {
28    fn new() -> Self {
29        Self {
30            vec_encoding: VecEncodingCheck::new(),
31            array_encoding: ArrayEncodingCheck::new(),
32            string_push: StringPushCheck::new(),
33            string_lowercase: StringLowercaseCheck::new(),
34        }
35    }
36
37    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
38        self.vec_encoding.check(graph, tcx);
39        self.array_encoding.check(graph, tcx);
40        self.string_push.check(graph, tcx);
41        self.string_lowercase.check(graph, tcx);
42    }
43
44    fn report(&self, graph: &Graph) {
45        self.vec_encoding.report(graph);
46        self.array_encoding.report(graph);
47        self.string_push.report(graph);
48        self.string_lowercase.report(graph);
49    }
50
51    fn cnt(&self) -> usize {
52        self.vec_encoding.cnt()
53            + self.array_encoding.cnt()
54            + self.string_lowercase.cnt()
55            + self.string_push.cnt()
56    }
57}
58
59fn report_encoding_bug(graph: &Graph, span: Span) {
60    OptReport::from_graph(graph)
61        .title("Unnecessary encoding checkings detected")
62        .annotate(Level::Error, span, "Checked here.")
63        .footer("Use unsafe APIs.")
64        .emit();
65}
66
67fn value_is_from_const(graph: &Graph, value_idx: Local) -> bool {
68    let mut edge_validator = |graph: &Graph, idx: EdgeIdx| {
69        let edge = &graph.edges[idx];
70        let dst_node = &graph.nodes[edge.dst];
71        let same_seq_edge_cnt = dst_node
72            .in_edges
73            .iter()
74            .filter(|edge_idx| graph.edges[**edge_idx].seq == edge.seq)
75            .count();
76        match same_seq_edge_cnt {
77            1 => Graph::always_true_edge_validator(graph, idx),
78            2 => {
79                if let EdgeOp::Index = edge.op {
80                    DFSStatus::Continue
81                } else {
82                    DFSStatus::Stop
83                }
84            }
85            _ => DFSStatus::Stop,
86        }
87    };
88    graph
89        .find_first_node(
90            value_idx,
91            Direction::Upside,
92            &mut |graph: &Graph, idx: Local| {
93                let node = &graph.nodes[idx];
94                node.ops.iter().any(|op| {
95                    if let NodeOp::Const(_, src_ty) = op {
96                        src_ty.contains("u8")
97                    } else {
98                        false
99                    }
100                })
101            },
102            &mut edge_validator,
103        )
104        .is_some()
105}