rapx/analysis/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::{
10        core::dataflow::{graph::*, *},
11        opt::OptCheck,
12    },
13    utils::log::{relative_pos_range, span_to_filename, span_to_line_number, span_to_source_code},
14};
15use annotate_snippets::{Level, Renderer, Snippet};
16
17use rustc_middle::{mir::Local, ty::TyCtxt};
18use rustc_span::Span;
19
20use array_encoding::ArrayEncodingCheck;
21use string_lowercase::StringLowercaseCheck;
22use string_push::StringPushCheck;
23use vec_encoding::VecEncodingCheck;
24
25pub struct EncodingCheck {
26    vec_encoding: VecEncodingCheck,
27    array_encoding: ArrayEncodingCheck,
28    string_push: StringPushCheck,
29    string_lowercase: StringLowercaseCheck,
30}
31
32impl OptCheck for EncodingCheck {
33    fn new() -> Self {
34        Self {
35            vec_encoding: VecEncodingCheck::new(),
36            array_encoding: ArrayEncodingCheck::new(),
37            string_push: StringPushCheck::new(),
38            string_lowercase: StringLowercaseCheck::new(),
39        }
40    }
41
42    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
43        self.vec_encoding.check(graph, tcx);
44        self.array_encoding.check(graph, tcx);
45        self.string_push.check(graph, tcx);
46        self.string_lowercase.check(graph, tcx);
47    }
48
49    fn report(&self, graph: &Graph) {
50        self.vec_encoding.report(graph);
51        self.array_encoding.report(graph);
52        self.string_push.report(graph);
53        self.string_lowercase.report(graph);
54    }
55
56    fn cnt(&self) -> usize {
57        self.vec_encoding.cnt()
58            + self.array_encoding.cnt()
59            + self.string_lowercase.cnt()
60            + self.string_push.cnt()
61    }
62}
63
64fn report_encoding_bug(graph: &Graph, span: Span) {
65    let code_source = span_to_source_code(graph.span);
66    let filename = span_to_filename(graph.span);
67    let snippet = Snippet::source(&code_source)
68        .line_start(span_to_line_number(graph.span))
69        .origin(&filename)
70        .fold(true)
71        .annotation(
72            Level::Error
73                .span(relative_pos_range(graph.span, span))
74                .label("Checked here."),
75        );
76    let message = Level::Warning
77        .title("Unnecessary encoding checkings detected")
78        .snippet(snippet)
79        .footer(Level::Help.title("Use unsafe APIs."));
80    let renderer = Renderer::styled();
81    println!("{}", renderer.render(message));
82}
83
84// Warning: WE APPROXIMATELY VIEW CONST U8s AS SAFE INPUT
85// which may cause wrong result.
86
87// todo: ascii chars are extracted from String variables
88fn value_is_from_const(graph: &Graph, value_idx: Local) -> bool {
89    let mut const_found = false;
90    let mut node_operator = |graph: &Graph, idx: Local| -> DFSStatus {
91        let node = &graph.nodes[idx];
92        for op in node.ops.iter() {
93            if let NodeOp::Const(_, src_ty) = op {
94                if src_ty.contains("u8") {
95                    const_found = true;
96                    return DFSStatus::Stop;
97                }
98            }
99        }
100        DFSStatus::Continue
101    };
102    let mut edge_validator = |graph: &Graph, idx: EdgeIdx| {
103        let edge = &graph.edges[idx];
104        let dst_node = &graph.nodes[edge.dst];
105        let same_seq_edge_cnt = dst_node
106            .in_edges
107            .iter()
108            .filter(|edge_idx| graph.edges[**edge_idx].seq == edge.seq)
109            .count();
110        match same_seq_edge_cnt {
111            1 => Graph::always_true_edge_validator(graph, idx),
112            2 => {
113                if let EdgeOp::Index = edge.op {
114                    DFSStatus::Continue
115                } else {
116                    DFSStatus::Stop
117                }
118            }
119            _ => DFSStatus::Stop,
120        }
121    };
122    let mut seen = HashSet::new();
123    graph.dfs(
124        value_idx,
125        Direction::Upside,
126        &mut node_operator,
127        &mut edge_validator,
128        false,
129        &mut seen,
130    );
131    const_found
132}