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 std::collections::HashSet;
7
8use crate::{
9    analysis::core::dataflow::{graph::*, *},
10    check::opt::OptCheck,
11    utils::log::{relative_pos_range, span_to_filename, span_to_line_number, span_to_source_code},
12};
13use annotate_snippets::{Level, Renderer, Snippet};
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    let code_source = span_to_source_code(graph.span);
64    let filename = span_to_filename(graph.span);
65    let snippet = Snippet::source(&code_source)
66        .line_start(span_to_line_number(graph.span))
67        .origin(&filename)
68        .fold(true)
69        .annotation(
70            Level::Error
71                .span(relative_pos_range(graph.span, span))
72                .label("Checked here."),
73        );
74    let message = Level::Warning
75        .title("Unnecessary encoding checkings detected")
76        .snippet(snippet)
77        .footer(Level::Help.title("Use unsafe APIs."));
78    let renderer = Renderer::styled();
79    println!("{}", renderer.render(message));
80}
81
82// Warning: WE APPROXIMATELY VIEW CONST U8s AS SAFE INPUT
83// which may cause wrong result.
84
85// todo: ascii chars are extracted from String variables
86fn value_is_from_const(graph: &Graph, value_idx: Local) -> bool {
87    let mut const_found = false;
88    let mut node_operator = |graph: &Graph, idx: Local| -> DFSStatus {
89        let node = &graph.nodes[idx];
90        for op in node.ops.iter() {
91            if let NodeOp::Const(_, src_ty) = op {
92                if src_ty.contains("u8") {
93                    const_found = true;
94                    return DFSStatus::Stop;
95                }
96            }
97        }
98        DFSStatus::Continue
99    };
100    let mut edge_validator = |graph: &Graph, idx: EdgeIdx| {
101        let edge = &graph.edges[idx];
102        let dst_node = &graph.nodes[edge.dst];
103        let same_seq_edge_cnt = dst_node
104            .in_edges
105            .iter()
106            .filter(|edge_idx| graph.edges[**edge_idx].seq == edge.seq)
107            .count();
108        match same_seq_edge_cnt {
109            1 => Graph::always_true_edge_validator(graph, idx),
110            2 => {
111                if let EdgeOp::Index = edge.op {
112                    DFSStatus::Continue
113                } else {
114                    DFSStatus::Stop
115                }
116            }
117            _ => DFSStatus::Stop,
118        }
119    };
120    let mut seen = HashSet::new();
121    graph.dfs(
122        value_idx,
123        Direction::Upside,
124        &mut node_operator,
125        &mut edge_validator,
126        false,
127        &mut seen,
128    );
129    const_found
130}