use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use super::types::{
AbstractState, AbstractTransformer, AbstractionFunction, ArrayBoundsAnalysis,
AssumeGuaranteeContract, Bound, ConcretizationFunction, DataflowAnalysis, DelayedWidening,
FixpointComputation, GaloisConnection, IntervalDomain, IntervalWidening, LoopBound,
NullPointerAnalysis, OctagonDomain, ParityDomain, PolyhedralDomain,
ProbabilisticAbstractDomain, ReachabilityAnalysis, SignDomain, TaintAnalysis,
TemplatePolyhedronDomain, ZonotopeDomain,
};
pub fn app(f: Expr, a: Expr) -> Expr {
Expr::App(Box::new(f), Box::new(a))
}
pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
app(app(f, a), b)
}
pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
app(app2(f, a, b), c)
}
pub fn cst(s: &str) -> Expr {
Expr::Const(Name::str(s), vec![])
}
pub fn prop() -> Expr {
Expr::Sort(Level::zero())
}
pub fn type0() -> Expr {
Expr::Sort(Level::succ(Level::zero()))
}
pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
}
pub fn arrow(a: Expr, b: Expr) -> Expr {
pi(BinderInfo::Default, "_", a, b)
}
pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
pi(BinderInfo::Implicit, name, dom, body)
}
pub fn bvar(n: u32) -> Expr {
Expr::BVar(n)
}
pub fn nat_ty() -> Expr {
cst("Nat")
}
pub fn bool_ty() -> Expr {
cst("Bool")
}
pub fn abstract_domain_ty() -> Expr {
impl_pi("A", type0(), type0())
}
pub fn abstract_lattice_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(app(cst("AbstractDomain"), bvar(0)), prop()),
)
}
pub fn interval_domain_ty() -> Expr {
type0()
}
pub fn octagon_domain_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn polyhedral_domain_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn sign_domain_ty() -> Expr {
type0()
}
pub fn parity_domain_ty() -> Expr {
type0()
}
pub fn abstract_join_ty() -> Expr {
impl_pi("A", type0(), arrow(bvar(0), arrow(bvar(1), bvar(2))))
}
pub fn abstract_meet_ty() -> Expr {
impl_pi("A", type0(), arrow(bvar(0), arrow(bvar(1), bvar(2))))
}
pub fn abstract_widen_ty() -> Expr {
impl_pi("A", type0(), arrow(bvar(0), arrow(bvar(1), bvar(2))))
}
pub fn abstract_narrow_ty() -> Expr {
impl_pi("A", type0(), arrow(bvar(0), arrow(bvar(1), bvar(2))))
}
pub fn abstract_state_ty() -> Expr {
type0()
}
pub fn abstract_transformer_ty() -> Expr {
arrow(cst("AbstractState"), cst("AbstractState"))
}
pub fn transfer_function_ty() -> Expr {
type0()
}
pub fn join_semilattice_ty() -> Expr {
arrow(
cst("AbstractState"),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn fixpoint_computation_ty() -> Expr {
arrow(
cst("TransferFunction"),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn soundness_condition_ty() -> Expr {
arrow(cst("AbstractTransformer"), prop())
}
pub fn galois_connection_ty() -> Expr {
impl_pi(
"C",
type0(),
impl_pi(
"A",
type0(),
arrow(
arrow(bvar(1), bvar(1)),
arrow(arrow(bvar(2), bvar(2)), prop()),
),
),
)
}
pub fn abstraction_function_ty() -> Expr {
impl_pi(
"C",
type0(),
impl_pi("A", type0(), arrow(app(cst("List"), bvar(1)), bvar(1))),
)
}
pub fn concretization_function_ty() -> Expr {
impl_pi(
"C",
type0(),
impl_pi("A", type0(), arrow(bvar(0), app(cst("List"), bvar(2)))),
)
}
pub fn optimal_abstraction_ty() -> Expr {
impl_pi(
"C",
type0(),
impl_pi("A", type0(), arrow(app(cst("List"), bvar(1)), bvar(1))),
)
}
pub fn galois_insertion_ty() -> Expr {
impl_pi(
"C",
type0(),
impl_pi(
"A",
type0(),
arrow(app2(cst("GaloisConnection"), bvar(1), bvar(0)), prop()),
),
)
}
pub fn dataflow_analysis_ty() -> Expr {
type0()
}
pub fn reachability_analysis_ty() -> Expr {
arrow(type0(), prop())
}
pub fn null_pointer_analysis_ty() -> Expr {
type0()
}
pub fn array_bounds_analysis_ty() -> Expr {
type0()
}
pub fn taint_analysis_ty() -> Expr {
type0()
}
pub fn live_variable_analysis_ty() -> Expr {
type0()
}
pub fn available_expr_analysis_ty() -> Expr {
type0()
}
pub fn interval_widening_ty() -> Expr {
arrow(
cst("IntervalDomain"),
arrow(cst("IntervalDomain"), cst("IntervalDomain")),
)
}
pub fn convex_hull_widening_ty() -> Expr {
arrow(
app(cst("PolyhedralDomain"), nat_ty()),
arrow(
app(cst("PolyhedralDomain"), nat_ty()),
app(cst("PolyhedralDomain"), nat_ty()),
),
)
}
pub fn delayed_widening_ty() -> Expr {
arrow(
nat_ty(),
arrow(
cst("AbstractState"),
arrow(cst("AbstractState"), cst("AbstractState")),
),
)
}
pub fn loop_bound_ty() -> Expr {
arrow(cst("AbstractState"), nat_ty())
}
pub fn build_env(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("AbstractDomain", abstract_domain_ty()),
("AbstractLattice", abstract_lattice_ty()),
("IntervalDomain", interval_domain_ty()),
("OctagonDomain", octagon_domain_ty()),
("PolyhedralDomain", polyhedral_domain_ty()),
("SignDomain", sign_domain_ty()),
("ParityDomain", parity_domain_ty()),
("AbstractJoin", abstract_join_ty()),
("AbstractMeet", abstract_meet_ty()),
("AbstractWiden", abstract_widen_ty()),
("AbstractNarrow", abstract_narrow_ty()),
("AbstractState", abstract_state_ty()),
("AbstractTransformer", abstract_transformer_ty()),
("TransferFunction", transfer_function_ty()),
("JoinSemilattice", join_semilattice_ty()),
("FixpointComputation", fixpoint_computation_ty()),
("SoundnessCondition", soundness_condition_ty()),
("GaloisConnection", galois_connection_ty()),
("AbstractionFunction", abstraction_function_ty()),
("ConcretizationFunction", concretization_function_ty()),
("OptimalAbstraction", optimal_abstraction_ty()),
("GaloisInsertion", galois_insertion_ty()),
("DataflowAnalysis", dataflow_analysis_ty()),
("ReachabilityAnalysis", reachability_analysis_ty()),
("NullPointerAnalysis", null_pointer_analysis_ty()),
("ArrayBoundsAnalysis", array_bounds_analysis_ty()),
("TaintAnalysis", taint_analysis_ty()),
("LiveVariableAnalysis", live_variable_analysis_ty()),
("AvailableExprAnalysis", available_expr_analysis_ty()),
("IntervalWidening", interval_widening_ty()),
("ConvexHullWidening", convex_hull_widening_ty()),
("DelayedWidening", delayed_widening_ty()),
("LoopBound", loop_bound_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
pub fn ellipsoid_domain_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn zonotope_domain_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), type0()))
}
pub fn template_polyhedron_domain_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), type0()))
}
pub fn reduced_product_domain_ty() -> Expr {
impl_pi(
"A",
type0(),
impl_pi("B", type0(), arrow(bvar(1), arrow(bvar(1), type0()))),
)
}
pub fn smashing_domain_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(app(cst("AbstractDomain"), bvar(0)), type0()),
)
}
pub fn powerset_lifting_domain_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(app(cst("AbstractDomain"), bvar(0)), type0()),
)
}
pub fn trace_abstraction_ty() -> Expr {
impl_pi("A", type0(), type0())
}
pub fn abstract_trace_ty() -> Expr {
type0()
}
pub fn trace_semantics_monotone_ty() -> Expr {
arrow(cst("AbstractTrace"), arrow(cst("AbstractTrace"), prop()))
}
pub fn thread_modular_analysis_ty() -> Expr {
arrow(nat_ty(), arrow(cst("AbstractState"), cst("AbstractState")))
}
pub fn interference_abstraction_ty() -> Expr {
arrow(
cst("AbstractState"),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn partial_order_reduction_abs_ty() -> Expr {
arrow(cst("AbstractState"), cst("AbstractState"))
}
pub fn lockset_analysis_ty() -> Expr {
type0()
}
pub fn widening_operator_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(
app(cst("AbstractDomain"), bvar(0)),
arrow(bvar(1), arrow(bvar(2), bvar(3))),
),
)
}
pub fn narrowing_operator_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(
app(cst("AbstractDomain"), bvar(0)),
arrow(bvar(1), arrow(bvar(2), bvar(3))),
),
)
}
pub fn extrapolation_lemma_ty() -> Expr {
impl_pi(
"A",
type0(),
arrow(app(cst("WideningOperator"), bvar(0)), prop()),
)
}
pub fn accelerated_fixpoint_ty() -> Expr {
arrow(cst("AbstractState"), cst("AbstractState"))
}
pub fn probabilistic_abstract_domain_ty() -> Expr {
type0()
}
pub fn abstract_distribution_ty() -> Expr {
impl_pi("A", type0(), type0())
}
pub fn abstract_expectation_ty() -> Expr {
arrow(
app(cst("AbstractDistribution"), type0()),
arrow(arrow(type0(), cst("Real")), cst("Real")),
)
}
pub fn probabilistic_soundness_ty() -> Expr {
arrow(app(cst("AbstractDistribution"), type0()), prop())
}
pub fn bdd_abstract_domain_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn sat_abstract_domain_ty() -> Expr {
type0()
}
pub fn symbolic_transformer_ty() -> Expr {
arrow(cst("SatAbstractDomain"), cst("SatAbstractDomain"))
}
pub fn abstract_model_checking_ty() -> Expr {
arrow(cst("AbstractState"), arrow(prop(), cst("Bool")))
}
pub fn separation_logic_abs_domain_ty() -> Expr {
type0()
}
pub fn abstract_heap_predicate_ty() -> Expr {
arrow(type0(), prop())
}
pub fn separating_conjunction_ty() -> Expr {
arrow(
app(cst("AbstractHeapPredicate"), type0()),
arrow(
app(cst("AbstractHeapPredicate"), type0()),
app(cst("AbstractHeapPredicate"), type0()),
),
)
}
pub fn shape_analysis_ty() -> Expr {
arrow(
cst("SeparationLogicAbsDomain"),
app(cst("AbstractHeapPredicate"), type0()),
)
}
pub fn higher_order_abstract_domain_ty() -> Expr {
arrow(arrow(type0(), type0()), type0())
}
pub fn abstract_closure_ty() -> Expr {
arrow(
cst("AbstractState"),
arrow(arrow(cst("AbstractState"), cst("AbstractState")), type0()),
)
}
pub fn closure_abstraction_ty() -> Expr {
arrow(
app2(
cst("AbstractClosure"),
cst("AbstractState"),
arrow(cst("AbstractState"), cst("AbstractState")),
),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn higher_order_fixpoint_ty() -> Expr {
arrow(
arrow(cst("AbstractState"), cst("AbstractState")),
cst("AbstractState"),
)
}
pub fn information_flow_lattice_ty() -> Expr {
type0()
}
pub fn non_interference_ty() -> Expr {
arrow(
cst("AbstractState"),
arrow(cst("InformationFlowLattice"), prop()),
)
}
pub fn declassification_policy_ty() -> Expr {
arrow(type0(), arrow(cst("InformationFlowLattice"), prop()))
}
pub fn secure_abstract_interpreter_ty() -> Expr {
arrow(
cst("AbstractState"),
arrow(cst("InformationFlowLattice"), prop()),
)
}
pub fn type_lattice_ty() -> Expr {
type0()
}
pub fn type_refinement_ty() -> Expr {
arrow(
cst("TypeLattice"),
arrow(app(cst("AbstractDomain"), type0()), type0()),
)
}
pub fn typed_abstract_transformer_ty() -> Expr {
arrow(
cst("TypeLattice"),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn deep_poly_domain_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn abstract_relu_ty() -> Expr {
arrow(
app(cst("DeepPolyDomain"), nat_ty()),
app(cst("DeepPolyDomain"), nat_ty()),
)
}
pub fn neural_network_verification_ty() -> Expr {
arrow(
app(cst("DeepPolyDomain"), nat_ty()),
arrow(prop(), cst("Bool")),
)
}
pub fn abstract_affine_transform_ty() -> Expr {
arrow(
nat_ty(),
arrow(
nat_ty(),
arrow(
app(cst("DeepPolyDomain"), nat_ty()),
app(cst("DeepPolyDomain"), nat_ty()),
),
),
)
}
pub fn assume_guarantee_contract_ty() -> Expr {
arrow(cst("AbstractState"), arrow(cst("AbstractState"), type0()))
}
pub fn contract_composition_ty() -> Expr {
let ag = app2(
cst("AssumeGuaranteeContract"),
cst("AbstractState"),
cst("AbstractState"),
);
arrow(ag.clone(), arrow(ag.clone(), ag))
}
pub fn summary_function_ty() -> Expr {
arrow(cst("AbstractState"), cst("AbstractState"))
}
pub fn composition_soundness_ty() -> Expr {
arrow(
cst("SummaryFunction"),
arrow(
app2(
cst("AssumeGuaranteeContract"),
cst("AbstractState"),
cst("AbstractState"),
),
prop(),
),
)
}
pub fn modular_fixpoint_ty() -> Expr {
arrow(
arrow(cst("AbstractState"), cst("AbstractState")),
arrow(cst("AbstractState"), cst("AbstractState")),
)
}
pub fn build_env_extended(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("EllipsoidDomain", ellipsoid_domain_ty()),
("ZonotopeDomain", zonotope_domain_ty()),
("TemplatePolyhedronDomain", template_polyhedron_domain_ty()),
("ReducedProductDomain", reduced_product_domain_ty()),
("SmashingDomain", smashing_domain_ty()),
("PowersetLiftingDomain", powerset_lifting_domain_ty()),
("TraceAbstraction", trace_abstraction_ty()),
("AbstractTrace", abstract_trace_ty()),
("TraceSemanticsMonotone", trace_semantics_monotone_ty()),
("ThreadModularAnalysis", thread_modular_analysis_ty()),
("InterferenceAbstraction", interference_abstraction_ty()),
("PartialOrderReductionAbs", partial_order_reduction_abs_ty()),
("LocksetAnalysis", lockset_analysis_ty()),
("WideningOperator", widening_operator_ty()),
("NarrowingOperator", narrowing_operator_ty()),
("ExtrapolationLemma", extrapolation_lemma_ty()),
("AcceleratedFixpoint", accelerated_fixpoint_ty()),
(
"ProbabilisticAbstractDomain",
probabilistic_abstract_domain_ty(),
),
("AbstractDistribution", abstract_distribution_ty()),
("AbstractExpectation", abstract_expectation_ty()),
("ProbabilisticSoundness", probabilistic_soundness_ty()),
("BddAbstractDomain", bdd_abstract_domain_ty()),
("SatAbstractDomain", sat_abstract_domain_ty()),
("SymbolicTransformer", symbolic_transformer_ty()),
("AbstractModelChecking", abstract_model_checking_ty()),
("SeparationLogicAbsDomain", separation_logic_abs_domain_ty()),
("AbstractHeapPredicate", abstract_heap_predicate_ty()),
("SeparatingConjunction", separating_conjunction_ty()),
("ShapeAnalysis", shape_analysis_ty()),
(
"HigherOrderAbstractDomain",
higher_order_abstract_domain_ty(),
),
("AbstractClosure", abstract_closure_ty()),
("ClosureAbstraction", closure_abstraction_ty()),
("HigherOrderFixpoint", higher_order_fixpoint_ty()),
("InformationFlowLattice", information_flow_lattice_ty()),
("NonInterference", non_interference_ty()),
("DeclassificationPolicy", declassification_policy_ty()),
(
"SecureAbstractInterpreter",
secure_abstract_interpreter_ty(),
),
("TypeLattice", type_lattice_ty()),
("TypeRefinement", type_refinement_ty()),
("TypedAbstractTransformer", typed_abstract_transformer_ty()),
("DeepPolyDomain", deep_poly_domain_ty()),
("AbstractRelu", abstract_relu_ty()),
(
"NeuralNetworkVerification",
neural_network_verification_ty(),
),
("AbstractAffineTransform", abstract_affine_transform_ty()),
("AssumeGuaranteeContract", assume_guarantee_contract_ty()),
("ContractComposition", contract_composition_ty()),
("SummaryFunction", summary_function_ty()),
("CompositionSoundness", composition_soundness_ty()),
("ModularFixpoint", modular_fixpoint_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
#[cfg(test)]
mod tests {
use super::*;
fn registered_env() -> Environment {
let mut env = Environment::new();
build_env(&mut env);
env
}
#[test]
fn test_abstract_domain_registered() {
let env = registered_env();
assert!(env.get(&Name::str("AbstractDomain")).is_some());
}
#[test]
fn test_interval_domain_registered() {
let env = registered_env();
assert!(env.get(&Name::str("IntervalDomain")).is_some());
}
#[test]
fn test_galois_connection_registered() {
let env = registered_env();
assert!(env.get(&Name::str("GaloisConnection")).is_some());
}
#[test]
fn test_sign_domain_join() {
assert_eq!(SignDomain::Pos.join(&SignDomain::Zero), SignDomain::NonNeg);
assert_eq!(SignDomain::Neg.join(&SignDomain::Pos), SignDomain::Top);
assert_eq!(SignDomain::Bottom.join(&SignDomain::Neg), SignDomain::Neg);
}
#[test]
fn test_parity_domain_add() {
assert_eq!(
ParityDomain::Even.add(&ParityDomain::Even),
ParityDomain::Even
);
assert_eq!(
ParityDomain::Odd.add(&ParityDomain::Odd),
ParityDomain::Even
);
assert_eq!(
ParityDomain::Even.add(&ParityDomain::Odd),
ParityDomain::Odd
);
}
#[test]
fn test_interval_join_widen() {
let a = IntervalDomain::new(Bound::Finite(0), Bound::Finite(5));
let b = IntervalDomain::new(Bound::Finite(3), Bound::Finite(10));
let j = a.join(&b);
assert_eq!(j.lower, Bound::Finite(0));
assert_eq!(j.upper, Bound::Finite(10));
let a2 = IntervalDomain::new(Bound::Finite(0), Bound::Finite(5));
let b2 = IntervalDomain::new(Bound::Finite(0), Bound::Finite(20));
let w = a2.widen(&b2);
assert_eq!(w.upper, Bound::PosInf);
}
#[test]
fn test_interval_contains() {
let i = IntervalDomain::new(Bound::Finite(1), Bound::Finite(10));
assert!(i.contains(5));
assert!(!i.contains(0));
assert!(!i.contains(11));
}
#[test]
fn test_galois_connection() {
let gc = GaloisConnection::interval_galois();
let abs = gc.abstract_of(&[1, 3, 5, 7]);
assert_eq!(abs.lower, Bound::Finite(1));
assert_eq!(abs.upper, Bound::Finite(7));
}
#[test]
fn test_abstract_state_widen() {
let mut s1 = AbstractState::bottom();
s1.set("x", IntervalDomain::new(Bound::Finite(0), Bound::Finite(5)));
let mut s2 = AbstractState::bottom();
s2.set(
"x",
IntervalDomain::new(Bound::Finite(0), Bound::Finite(10)),
);
let w = s1.widen(&s2);
assert_eq!(w.get("x").upper, Bound::PosInf);
}
#[test]
fn test_taint_analysis() {
let mut ta = TaintAnalysis::new();
ta.add_source("user_input");
assert!(ta.is_tainted("user_input"));
ta.propagate("result", &["user_input", "constant"]);
assert!(ta.is_tainted("result"));
}
#[test]
fn test_delayed_widening() {
let a = IntervalDomain::new(Bound::Finite(0), Bound::Finite(5));
let b = IntervalDomain::new(Bound::Finite(0), Bound::Finite(10));
let mut dw = DelayedWidening::new(2);
let r1 = dw.apply(&a, &b);
assert_eq!(r1.upper, Bound::Finite(10));
let r2 = dw.apply(&a, &b);
assert_eq!(r2.upper, Bound::Finite(10));
let r3 = dw.apply(&a, &b);
assert_eq!(r3.upper, Bound::PosInf);
}
#[test]
fn test_octagon_satisfiable() {
let mut oct = OctagonDomain::top(2);
oct.add_upper_bound(0, 10);
assert!(oct.is_satisfiable());
}
#[test]
fn test_polyhedral_contains() {
let mut poly = PolyhedralDomain::top(2);
poly.add_constraint(vec![1.0, 0.0], 5.0);
poly.add_constraint(vec![0.0, 1.0], 3.0);
assert!(poly.contains(&[4.0, 2.0]));
assert!(!poly.contains(&[6.0, 2.0]));
}
}