use crate::helpers::mir_scan::Checkpoint;
use crate::verify::contract::Property;
use crate::verify::report::CheckResult;
use crate::verify::vm::state::VmState;
use z3::{SatResult, Solver, ast::Int};
use super::PropertyChecker;
impl PropertyChecker {
fn check_utf8_alloc<'z3, 'tcx>(
&self,
vm_state: &VmState<'z3, 'tcx>,
solver: &Solver<'z3>,
alloc_id: crate::verify::vm::state::AllocId,
) -> CheckResult {
if vm_state.alloc(alloc_id).facts.dead {
return CheckResult::Failed;
}
let byte_pairs = vm_state.alloc_byte_values(alloc_id);
if byte_pairs.is_empty() {
return CheckResult::ProvedByRule; }
let bytes: Vec<Int<'z3>> = byte_pairs.iter().map(|(_, t)| (*t).clone()).collect();
let valid = super::utf8_validity(vm_state.z3_ctx, &bytes);
solver.push();
solver.assert(&valid);
let r = solver.check();
solver.pop(1);
match r {
SatResult::Unsat => CheckResult::Failed,
_ => CheckResult::ProvedByRule,
}
}
pub(super) fn check_valid_string<'z3, 'tcx>(
&self,
vm_state: &VmState<'z3, 'tcx>,
solver: &Solver<'z3>,
checkpoint: &Checkpoint<'tcx>,
property: &Property<'tcx>,
) -> CheckResult {
if let Some(count) = property
.args()
.get(2)
.and_then(|a| self.resolve_arg_term(vm_state, checkpoint, a))
{
if count.as_u64() == Some(0) {
return CheckResult::ProvedByRule;
}
}
let Some(value) = self.target_value(vm_state, checkpoint, property) else {
return CheckResult::ProvedByRule;
};
if let Some(alloc_id) = value.provenance_alloc_id() {
return self.check_utf8_alloc(vm_state, solver, alloc_id);
}
if let Some(local) = vm_state.find_local_by_address(&value.z3_term) {
if let Some((alloc_id, _end_offset)) = vm_state.iter_utf8_buffer(local) {
return self.check_utf8_alloc(vm_state, solver, alloc_id);
}
}
CheckResult::ProvedByRule
}
}