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