rapx/check/opt/checking/encoding_checking/
array_encoding.rs1use std::collections::HashSet;
2
3
4use rustc_middle::{mir::Local, ty::TyCtxt};
5use rustc_span::Span;
6
7use super::{report_encoding_bug, value_is_from_const};
8use crate::analysis::dataflow::*;
9use crate::check::opt::OptCheck;
10
11crate::def_paths! {
12 str_from_utf8: "std::str::from_utf8",
13}
14
15
16pub struct ArrayEncodingCheck {
17 record: Vec<Span>,
18}
19
20fn extract_ancestor_set_if_is_str_from(
21 graph: &Graph,
22 node_idx: Local,
23 node: &GraphNode,
24) -> Option<HashSet<Local>> {
25 let def_paths = DEFPATHS.get().unwrap();
26 for op in node.ops.iter() {
27 if let NodeOp::Call(def_id) = op {
28 if *def_id == def_paths.str_from_utf8.last_def_id() {
29 return Some(graph.collect_ancestor_locals(node_idx, false));
30 }
31 }
32 }
33 None
34}
35
36fn is_valid_index_edge(graph: &Graph, edge: &GraphEdge) -> bool {
37 if let EdgeOp::Index = edge.op {
38 let dst_node = &graph.nodes[edge.dst];
40 if dst_node.in_edges.len() > 2 {
41 let rvalue_edge_idx = dst_node.in_edges[2];
43 let rvalue_idx = graph.edges[rvalue_edge_idx].src;
44 if value_is_from_const(graph, rvalue_idx) {
45 return true;
46 }
47 }
48 }
49 false
50}
51
52impl OptCheck for ArrayEncodingCheck {
53 fn new() -> Self {
54 Self { record: Vec::new() }
55 }
56
57 fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
58 let _ = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
59 let common_ancestor = graph
60 .edges
61 .iter()
62 .filter_map(|edge| {
63 if is_valid_index_edge(graph, edge) {
65 Some(graph.collect_ancestor_locals(edge.src, true))
66 } else {
67 None
68 }
69 })
70 .reduce(|set1, set2| set1.into_iter().filter(|k| set2.contains(k)).collect());
71
72 if let Some(common_ancestor) = common_ancestor {
73 for (node_idx, node) in graph.nodes.iter_enumerated() {
74 if let Some(str_from_ancestor_set) =
75 extract_ancestor_set_if_is_str_from(graph, node_idx, node)
76 {
77 if !common_ancestor
78 .intersection(&str_from_ancestor_set)
79 .next()
80 .is_some()
81 {
82 self.record.clear();
83 return;
84 }
85 self.record.push(node.span);
86 }
87 }
88 }
89 }
90
91 fn report(&self, graph: &Graph) {
92 for span in self.record.iter() {
93 report_encoding_bug(graph, *span);
94 }
95 }
96
97 fn cnt(&self) -> usize {
98 self.record.len()
99 }
100}