rapx 0.7.31

A static analysis platform for Rust program analysis and verification
pub mod array_encoding;
pub mod string_lowercase;
pub mod string_push;
pub mod vec_encoding;

use crate::{
    analysis::dataflow::*,
    check::opt::OptCheck,
};

use annotate_snippets::Level;

use crate::check::opt::report::OptReport;

use rustc_middle::{mir::Local, ty::TyCtxt};
use rustc_span::Span;

use array_encoding::ArrayEncodingCheck;
use string_lowercase::StringLowercaseCheck;
use string_push::StringPushCheck;
use vec_encoding::VecEncodingCheck;

pub struct EncodingCheck {
    vec_encoding: VecEncodingCheck,
    array_encoding: ArrayEncodingCheck,
    string_push: StringPushCheck,
    string_lowercase: StringLowercaseCheck,
}

impl OptCheck for EncodingCheck {
    fn new() -> Self {
        Self {
            vec_encoding: VecEncodingCheck::new(),
            array_encoding: ArrayEncodingCheck::new(),
            string_push: StringPushCheck::new(),
            string_lowercase: StringLowercaseCheck::new(),
        }
    }

    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
        self.vec_encoding.check(graph, tcx);
        self.array_encoding.check(graph, tcx);
        self.string_push.check(graph, tcx);
        self.string_lowercase.check(graph, tcx);
    }

    fn report(&self, graph: &Graph) {
        self.vec_encoding.report(graph);
        self.array_encoding.report(graph);
        self.string_push.report(graph);
        self.string_lowercase.report(graph);
    }

    fn cnt(&self) -> usize {
        self.vec_encoding.cnt()
            + self.array_encoding.cnt()
            + self.string_lowercase.cnt()
            + self.string_push.cnt()
    }
}

fn report_encoding_bug(graph: &Graph, span: Span) {
    OptReport::from_graph(graph)
        .title("Unnecessary encoding checkings detected")
        .annotate(Level::Error, span, "Checked here.")
        .footer("Use unsafe APIs.")
        .emit();
}

fn value_is_from_const(graph: &Graph, value_idx: Local) -> bool {
    let mut edge_validator = |graph: &Graph, idx: EdgeIdx| {
        let edge = &graph.edges[idx];
        let dst_node = &graph.nodes[edge.dst];
        let same_seq_edge_cnt = dst_node
            .in_edges
            .iter()
            .filter(|edge_idx| graph.edges[**edge_idx].seq == edge.seq)
            .count();
        match same_seq_edge_cnt {
            1 => Graph::always_true_edge_validator(graph, idx),
            2 => {
                if let EdgeOp::Index = edge.op {
                    DFSStatus::Continue
                } else {
                    DFSStatus::Stop
                }
            }
            _ => DFSStatus::Stop,
        }
    };
    graph.find_first_node(
        value_idx,
        Direction::Upside,
        &mut |graph: &Graph, idx: Local| {
            let node = &graph.nodes[idx];
            node.ops.iter().any(|op| {
                if let NodeOp::Const(_, src_ty) = op {
                    src_ty.contains("u8")
                } else {
                    false
                }
            })
        },
        &mut edge_validator,
    ).is_some()
}