use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use std::collections::{BTreeSet, HashSet, VecDeque};
use super::types::{
AndersenPTA, ConstPropState, EraserState, FixpointSolver, IFCTracker, Interval, NullTracker,
Nullability, PDGraph, SecurityLevel, Sign, TaintState, TypestateAutomaton,
};
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 bvar(n: u32) -> Expr {
Expr::BVar(n)
}
pub fn nat_ty() -> Expr {
cst("Nat")
}
pub fn bool_ty() -> Expr {
cst("Bool")
}
pub fn string_ty() -> Expr {
cst("String")
}
pub fn list_ty(elem: Expr) -> Expr {
app(cst("List"), elem)
}
pub fn option_ty(elem: Expr) -> Expr {
app(cst("Option"), elem)
}
pub fn set_ty(elem: Expr) -> Expr {
app(cst("Set"), elem)
}
pub fn pair_ty(a: Expr, b: Expr) -> Expr {
app2(cst("Prod"), a, b)
}
pub fn lattice_ty() -> Expr {
arrow(type0(), type0())
}
pub fn lattice_bottom_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(app(cst("Lattice"), bvar(0)), bvar(1)),
)
}
pub fn lattice_top_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(app(cst("Lattice"), bvar(0)), bvar(1)),
)
}
pub fn lattice_join_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(
app(cst("Lattice"), bvar(0)),
arrow(bvar(1), arrow(bvar(2), bvar(3))),
),
)
}
pub fn lattice_meet_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(
app(cst("Lattice"), bvar(0)),
arrow(bvar(1), arrow(bvar(2), bvar(3))),
),
)
}
pub fn lattice_leq_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(
app(cst("Lattice"), bvar(0)),
arrow(bvar(1), arrow(bvar(2), prop())),
),
)
}
pub fn moore_family_ty() -> Expr {
pi(
BinderInfo::Default,
"A",
type0(),
arrow(set_ty(set_ty(bvar(0))), prop()),
)
}
pub fn complete_lattice_galois_ty() -> Expr {
pi(
BinderInfo::Default,
"L",
type0(),
arrow(
app(cst("GaloisConn"), bvar(0)),
app(cst("CompleteLattice"), bvar(1)),
),
)
}
pub fn concrete_semantics_ty() -> Expr {
arrow(cst("Program"), set_ty(cst("ConcreteState")))
}
pub fn abstract_semantics_ty() -> Expr {
arrow(cst("Program"), cst("AbsDom"))
}
pub fn galois_connection_ty() -> Expr {
pair_ty(
arrow(cst("ConcreteState"), cst("AbsDom")),
arrow(cst("AbsDom"), cst("ConcreteState")),
)
}
pub fn abstraction_ty() -> Expr {
arrow(concrete_semantics_ty(), cst("AbsDom"))
}
pub fn concretization_ty() -> Expr {
arrow(cst("AbsDom"), concrete_semantics_ty())
}
pub fn galois_insertion_ty() -> Expr {
arrow(galois_connection_ty(), prop())
}
pub fn widening_ty() -> Expr {
arrow(cst("AbsDom"), arrow(cst("AbsDom"), cst("AbsDom")))
}
pub fn narrowing_ty() -> Expr {
arrow(cst("AbsDom"), arrow(cst("AbsDom"), cst("AbsDom")))
}
pub fn widening_terminates_ty() -> Expr {
pi(
BinderInfo::Default,
"f",
arrow(cst("AbsDom"), cst("AbsDom")),
app(
cst("Terminates"),
app2(cst("fixpoint_widen"), bvar(0), cst("Widening")),
),
)
}
pub fn abstract_interp_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(
app(cst("Leq"), app(cst("α"), app(cst("collect"), bvar(0)))),
app(cst("abs_semantics"), bvar(0)),
),
)
}
pub fn narrowing_refines_post_ty() -> Expr {
pi(
BinderInfo::Default,
"x",
cst("AbsDom"),
pi(
BinderInfo::Default,
"y",
cst("AbsDom"),
arrow(
app2(cst("Leq"), bvar(0), bvar(1)),
app(
app(
cst("Leq"),
app2(cst("Narrowing"), bvar(1), app(cst("f"), bvar(2))),
),
bvar(2),
),
),
),
)
}
pub fn heap_graph_ty() -> Expr {
type0()
}
pub fn heap_node_ty() -> Expr {
type0()
}
pub fn sharing_pred_ty() -> Expr {
arrow(
heap_graph_ty(),
arrow(heap_node_ty(), arrow(heap_node_ty(), prop())),
)
}
pub fn cyclic_pred_ty() -> Expr {
arrow(heap_graph_ty(), arrow(heap_node_ty(), prop()))
}
pub fn shape_descriptor_ty() -> Expr {
type0()
}
pub fn shape_join_ty() -> Expr {
arrow(
shape_descriptor_ty(),
arrow(shape_descriptor_ty(), shape_descriptor_ty()),
)
}
pub fn shape_transfer_ty() -> Expr {
arrow(
cst("HeapOp"),
arrow(shape_descriptor_ty(), shape_descriptor_ty()),
)
}
pub fn shape_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"op",
cst("HeapOp"),
pi(
BinderInfo::Default,
"s",
shape_descriptor_ty(),
app(
cst("OverApprox"),
app2(cst("shape_transfer"), bvar(1), bvar(0)),
),
),
)
}
pub fn three_valued_ty() -> Expr {
type0()
}
pub fn must_alias_ty() -> Expr {
arrow(
heap_graph_ty(),
arrow(heap_node_ty(), arrow(heap_node_ty(), three_valued_ty())),
)
}
pub fn alloc_site_ty() -> Expr {
nat_ty()
}
pub fn points_to_ty() -> Expr {
arrow(cst("Var"), set_ty(alloc_site_ty()))
}
pub fn andersen_analysis_ty() -> Expr {
arrow(cst("Program"), points_to_ty())
}
pub fn steensgaard_analysis_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), cst("Var")))
}
pub fn andersen_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Sound"), app(cst("AndersenAnalysis"), bvar(0))),
)
}
pub fn steensgaard_sub_andersen_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(
app(cst("Leq"), app(cst("SteensgaardAnalysis"), bvar(0))),
app(cst("AndersenAnalysis"), bvar(0)),
),
)
}
pub fn andersen_cubic_ty() -> Expr {
app(
cst("TimeComplexity"),
app(cst("CubicN"), cst("AndersenAnalysis")),
)
}
pub fn steensgaard_almost_linear_ty() -> Expr {
app(
cst("TimeComplexity"),
app(cst("InvAckermann"), cst("SteensgaardAnalysis")),
)
}
pub fn alias_result_ty() -> Expr {
arrow(cst("Var"), arrow(cst("Var"), prop()))
}
pub fn may_alias_ty() -> Expr {
arrow(
cst("Program"),
arrow(cst("Var"), arrow(cst("Var"), bool_ty())),
)
}
pub fn must_alias_pair_ty() -> Expr {
arrow(
cst("Program"),
arrow(cst("Var"), arrow(cst("Var"), bool_ty())),
)
}
pub fn type_based_alias_ty() -> Expr {
arrow(cst("IRType"), arrow(cst("IRType"), bool_ty()))
}
pub fn no_alias_ty() -> Expr {
arrow(cst("Var"), arrow(cst("Var"), prop()))
}
pub fn alias_undecidable_ty() -> Expr {
app(cst("Undecidable"), cst("ExactAliasAnalysis"))
}
pub fn soft_type_ty() -> Expr {
type0()
}
pub fn soft_type_check_ty() -> Expr {
arrow(cst("Program"), arrow(soft_type_ty(), bool_ty()))
}
pub fn refinement_type_ty() -> Expr {
arrow(type0(), arrow(arrow(bvar(0), prop()), type0()))
}
pub fn effect_type_ty() -> Expr {
arrow(type0(), arrow(cst("EffectSet"), type0()))
}
pub fn effect_subtype_ty() -> Expr {
arrow(effect_type_ty(), arrow(effect_type_ty(), prop()))
}
pub fn liquid_haskell_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("liquid_type_check"), bvar(0)),
app(cst("no_runtime_errors"), bvar(1)),
),
)
}
pub fn call_site_ty() -> Expr {
nat_ty()
}
pub fn abstract_closure_ty() -> Expr {
type0()
}
pub fn zero_cfa_ty() -> Expr {
arrow(
cst("Program"),
arrow(call_site_ty(), set_ty(abstract_closure_ty())),
)
}
pub fn k_cfa_ty() -> Expr {
arrow(
nat_ty(),
arrow(
cst("Program"),
arrow(
pair_ty(call_site_ty(), list_ty(call_site_ty())),
set_ty(abstract_closure_ty()),
),
),
)
}
pub fn cfa_overapprox_ty() -> Expr {
pi(
BinderInfo::Default,
"k",
nat_ty(),
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Overapproximates"), app2(cst("KCFA"), bvar(1), bvar(0))),
),
)
}
pub fn cfa_monotone_k_ty() -> Expr {
pi(
BinderInfo::Default,
"k",
nat_ty(),
app(
app(cst("Leq"), app2(cst("KCFA"), bvar(0), cst("prog"))),
app2(cst("KCFA"), app(cst("Succ"), bvar(0)), cst("prog")),
),
)
}
pub fn k_cfa_complexity_ty() -> Expr {
pi(
BinderInfo::Default,
"k",
nat_ty(),
arrow(
app(cst("Ge"), app2(cst("Ge"), bvar(0), nat_ty())),
app(cst("EXPTIMEComplete"), app(cst("KCFA"), bvar(1))),
),
)
}
pub fn effect_ty() -> Expr {
type0()
}
pub fn effect_set_ty() -> Expr {
set_ty(effect_ty())
}
pub fn read_effect_ty() -> Expr {
arrow(cst("Var"), effect_ty())
}
pub fn write_effect_ty() -> Expr {
arrow(cst("Var"), effect_ty())
}
pub fn exn_effect_ty() -> Expr {
arrow(cst("ExnType"), effect_ty())
}
pub fn infer_effects_ty() -> Expr {
arrow(cst("Program"), cst("EffectMap"))
}
pub fn effect_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(
app(cst("Superset"), app(cst("infer_effects"), bvar(0))),
app(cst("actual_effects"), bvar(0)),
),
)
}
pub fn pure_function_ty() -> Expr {
arrow(cst("Expr"), prop())
}
pub fn resource_type_ty() -> Expr {
type0()
}
pub fn usage_annotation_ty() -> Expr {
type0()
}
pub fn linear_type_ty() -> Expr {
arrow(resource_type_ty(), prop())
}
pub fn affine_type_ty() -> Expr {
arrow(resource_type_ty(), prop())
}
pub fn resource_usage_analysis_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), usage_annotation_ty()))
}
pub fn leak_freedom_ty() -> Expr {
arrow(cst("Program"), prop())
}
pub fn linear_type_leak_free_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("WellTypedLinear"), bvar(0)),
app(cst("LeakFreedom"), bvar(1)),
),
)
}
pub fn usage_count_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Sound"), app(cst("ResourceUsageAnalysis"), bvar(0))),
)
}
pub fn thread_ty() -> Expr {
nat_ty()
}
pub fn lock_set_ty() -> Expr {
set_ty(nat_ty())
}
pub fn happens_before_ty() -> Expr {
arrow(cst("Event"), arrow(cst("Event"), prop()))
}
pub fn data_race_ty() -> Expr {
arrow(cst("Event"), arrow(cst("Event"), prop()))
}
pub fn eraser_lock_set_ty() -> Expr {
arrow(thread_ty(), arrow(cst("MemLoc"), lock_set_ty()))
}
pub fn eraser_invariant_ty() -> Expr {
pi(
BinderInfo::Default,
"v",
cst("MemLoc"),
arrow(
app(cst("NonEmpty"), app(cst("C"), bvar(0))),
app(cst("NoRace"), bvar(1)),
),
)
}
pub fn tsan_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("HasRace"), bvar(0)),
app(cst("TSanReports"), bvar(1)),
),
)
}
pub fn data_race_freedom_ty() -> Expr {
arrow(cst("Program"), prop())
}
pub fn drf_sequential_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("DataRaceFreedom"), bvar(0)),
app(cst("SeqConsistent"), bvar(1)),
),
)
}
pub fn taint_source_ty() -> Expr {
type0()
}
pub fn taint_sink_ty() -> Expr {
type0()
}
pub fn sanitizer_ty() -> Expr {
type0()
}
pub fn taint_label_ty() -> Expr {
arrow(cst("Var"), bool_ty())
}
pub fn taint_propagation_ty() -> Expr {
arrow(cst("Program"), arrow(taint_label_ty(), taint_label_ty()))
}
pub fn taint_violation_ty() -> Expr {
arrow(
cst("Program"),
arrow(
taint_label_ty(),
arrow(set_ty(pair_ty(cst("Var"), taint_sink_ty())), prop()),
),
)
}
pub fn taint_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Sound"), app(cst("TaintPropagation"), bvar(0))),
)
}
pub fn taint_no_false_neg_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("RealViolation"), bvar(0)),
app(cst("Reported"), bvar(1)),
),
)
}
pub fn sep_logic_heap_ty() -> Expr {
arrow(cst("Addr"), option_ty(cst("Val")))
}
pub fn sep_conj_ty() -> Expr {
arrow(
arrow(sep_logic_heap_ty(), prop()),
arrow(
arrow(sep_logic_heap_ty(), prop()),
arrow(sep_logic_heap_ty(), prop()),
),
)
}
pub fn sep_imp_ty() -> Expr {
arrow(
arrow(sep_logic_heap_ty(), prop()),
arrow(
arrow(sep_logic_heap_ty(), prop()),
arrow(sep_logic_heap_ty(), prop()),
),
)
}
pub fn points_to_cell_ty() -> Expr {
arrow(
cst("Addr"),
arrow(cst("Val"), arrow(sep_logic_heap_ty(), prop())),
)
}
pub fn frame_rule_ty() -> Expr {
pi(
BinderInfo::Default,
"P",
arrow(sep_logic_heap_ty(), prop()),
pi(
BinderInfo::Default,
"Q",
arrow(sep_logic_heap_ty(), prop()),
pi(
BinderInfo::Default,
"R",
arrow(sep_logic_heap_ty(), prop()),
arrow(
app3(cst("HoareTriple"), bvar(2), cst("prog"), bvar(1)),
app3(
cst("HoareTriple"),
app2(cst("SepConj"), bvar(2), bvar(0)),
cst("prog"),
app2(cst("SepConj"), bvar(1), bvar(0)),
),
),
),
),
)
}
pub fn heap_shape_tree_pred_ty() -> Expr {
arrow(heap_node_ty(), arrow(sep_logic_heap_ty(), prop()))
}
pub fn memory_safety_ty() -> Expr {
arrow(
cst("Program"),
arrow(arrow(sep_logic_heap_ty(), prop()), prop()),
)
}
pub fn ownership_transfer_ty() -> Expr {
arrow(
arrow(sep_logic_heap_ty(), prop()),
arrow(arrow(sep_logic_heap_ty(), prop()), prop()),
)
}
pub fn typestate_ty() -> Expr {
type0()
}
pub fn typestate_protocol_ty() -> Expr {
arrow(typestate_ty(), set_ty(typestate_ty()))
}
pub fn typestate_transition_ty() -> Expr {
arrow(
typestate_ty(),
arrow(cst("Op"), arrow(typestate_ty(), prop())),
)
}
pub fn typestate_check_ty() -> Expr {
arrow(cst("Program"), arrow(typestate_protocol_ty(), prop()))
}
pub fn must_use_resource_ty() -> Expr {
arrow(typestate_ty(), prop())
}
pub fn typestate_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("TypestateCheck"), bvar(0)),
app(cst("NoProtocolViolation"), bvar(1)),
),
)
}
pub fn region_ty() -> Expr {
nat_ty()
}
pub fn region_annotation_ty() -> Expr {
arrow(cst("Expr"), region_ty())
}
pub fn escape_analysis_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), bool_ty()))
}
pub fn region_inference_ty() -> Expr {
arrow(cst("Program"), region_annotation_ty())
}
pub fn escape_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
pi(
BinderInfo::Default,
"v",
cst("Var"),
arrow(
app(
app(cst("Not"), app2(cst("EscapeAnalysis"), bvar(1), bvar(0))),
nat_ty(),
),
app2(cst("StackAllocated"), bvar(1), bvar(0)),
),
),
)
}
pub fn region_subtyping_ty() -> Expr {
arrow(region_ty(), arrow(region_ty(), prop()))
}
pub fn monadic_effect_ty() -> Expr {
arrow(type0(), arrow(effect_set_ty(), type0()))
}
pub fn graded_monad_ty() -> Expr {
arrow(arrow(effect_set_ty(), arrow(type0(), type0())), prop())
}
pub fn capability_set_ty() -> Expr {
set_ty(cst("Capability"))
}
pub fn capability_judgment_ty() -> Expr {
arrow(
cst("Context"),
arrow(cst("Expr"), arrow(effect_type_ty(), prop())),
)
}
pub fn effect_polymorphism_ty() -> Expr {
pi(
BinderInfo::Default,
"f",
effect_set_ty(),
pi(
BinderInfo::Default,
"g",
effect_set_ty(),
pi(
BinderInfo::Default,
"T",
type0(),
arrow(
app2(cst("HasEffectType"), bvar(0), bvar(2)),
app2(
cst("HasEffectType"),
bvar(0),
app2(cst("EffectUnion"), bvar(2), bvar(1)),
),
),
),
),
)
}
pub fn algebraic_effect_handler_ty() -> Expr {
arrow(effect_set_ty(), arrow(type0(), type0()))
}
pub fn gradual_type_ty() -> Expr {
type0()
}
pub fn unknown_type_ty() -> Expr {
gradual_type_ty()
}
pub fn consistency_rel_ty() -> Expr {
arrow(gradual_type_ty(), arrow(gradual_type_ty(), prop()))
}
pub fn cast_insertion_ty() -> Expr {
arrow(cst("GradualExpr"), cst("StaticExpr"))
}
pub fn cast_correctness_ty() -> Expr {
pi(
BinderInfo::Default,
"e",
cst("GradualExpr"),
app(
app(
cst("Eq"),
app(cst("eval"), app(cst("CastInsertion"), bvar(0))),
),
app(cst("gradual_eval"), bvar(0)),
),
)
}
pub fn blame_theorem_ty() -> Expr {
pi(
BinderInfo::Default,
"e",
cst("GradualExpr"),
arrow(
app(cst("CastFails"), bvar(0)),
app(cst("BlameCorrect"), bvar(1)),
),
)
}
pub fn liquid_type_ty() -> Expr {
arrow(
cst("BaseType"),
arrow(cst("Qualifier"), cst("RefinementType")),
)
}
pub fn qualifier_instantiation_ty() -> Expr {
arrow(
cst("Template"),
arrow(cst("Substitution"), cst("Qualifier")),
)
}
pub fn subtyping_refinement_ty() -> Expr {
arrow(cst("RefinementType"), arrow(cst("RefinementType"), prop()))
}
pub fn refinement_inference_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), cst("RefinementType")))
}
pub fn liquid_type_complete_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("QualifierSetFinite"), bvar(0)),
app(cst("RefinementInferenceComplete"), bvar(1)),
),
)
}
pub fn security_label_ty() -> Expr {
type0()
}
pub fn secrecy_lattice_ty() -> Expr {
arrow(security_label_ty(), arrow(security_label_ty(), prop()))
}
pub fn label_env_ty() -> Expr {
arrow(cst("Var"), security_label_ty())
}
pub fn non_interference_ty() -> Expr {
arrow(cst("Program"), arrow(label_env_ty(), prop()))
}
pub fn declassification_ty() -> Expr {
arrow(
cst("Expr"),
arrow(security_label_ty(), arrow(security_label_ty(), prop())),
)
}
pub fn ifc_type_system_ty() -> Expr {
arrow(
cst("Context"),
arrow(cst("Expr"), arrow(cst("LabeledType"), prop())),
)
}
pub fn ni_theorem_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
pi(
BinderInfo::Default,
"env",
label_env_ty(),
arrow(
app2(cst("IFC_typed"), bvar(1), bvar(0)),
app2(cst("NonInterference"), bvar(2), bvar(1)),
),
),
)
}
pub fn constant_folding_ty() -> Expr {
arrow(cst("Expr"), cst("Expr"))
}
pub fn constant_propagation_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), option_ty(cst("Val"))))
}
pub fn const_fold_correct_ty() -> Expr {
pi(
BinderInfo::Default,
"e",
cst("Expr"),
app(
app(
cst("Eq"),
app(cst("eval"), app(cst("ConstantFolding"), bvar(0))),
),
app(cst("eval"), bvar(0)),
),
)
}
pub fn interval_domain_ty() -> Expr {
type0()
}
pub fn bitfield_domain_ty() -> Expr {
type0()
}
pub fn value_range_analysis_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), interval_domain_ty()))
}
pub fn vra_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Sound"), app(cst("ValueRangeAnalysis"), bvar(0))),
)
}
pub fn nullability_annotation_ty() -> Expr {
arrow(type0(), arrow(bool_ty(), type0()))
}
pub fn null_pointer_analysis_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), three_valued_ty()))
}
pub fn definite_assignment_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Var"), prop()))
}
pub fn null_safety_ty() -> Expr {
arrow(cst("Program"), prop())
}
pub fn null_analysis_sound_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
app(cst("Sound"), app(cst("NullPointerAnalysis"), bvar(0))),
)
}
pub fn lock_order_ty() -> Expr {
arrow(cst("Lock"), arrow(cst("Lock"), prop()))
}
pub fn deadlock_freedom_ty() -> Expr {
arrow(cst("Program"), prop())
}
pub fn lock_order_acyclic_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("AcyclicLockOrder"), bvar(0)),
app(cst("DeadlockFreedom"), bvar(1)),
),
)
}
pub fn atomic_block_ty() -> Expr {
arrow(cst("Program"), arrow(cst("Stmt"), prop()))
}
pub fn atomicity_serializability_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
pi(
BinderInfo::Default,
"s",
cst("Stmt"),
arrow(
app2(cst("AtomicBlock"), bvar(1), bvar(0)),
app2(cst("SerializableExec"), bvar(2), bvar(1)),
),
),
)
}
pub fn lock_set_analysis_ty() -> Expr {
arrow(
cst("Program"),
arrow(thread_ty(), arrow(cst("MemLoc"), lock_set_ty())),
)
}
pub fn ownership_type_ty() -> Expr {
type0()
}
pub fn borrow_kind_ty() -> Expr {
type0()
}
pub fn lifetime_ty() -> Expr {
nat_ty()
}
pub fn borrow_check_ty() -> Expr {
arrow(cst("Program"), prop())
}
pub fn ownership_unique_ty() -> Expr {
arrow(ownership_type_ty(), prop())
}
pub fn borrow_check_mem_safe_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
arrow(
app(cst("BorrowCheck"), bvar(0)),
app(cst("MemorySafe"), bvar(1)),
),
)
}
pub fn lifetime_subtyping_ty() -> Expr {
arrow(lifetime_ty(), arrow(lifetime_ty(), prop()))
}
pub fn non_lexical_lifetime_ty() -> Expr {
arrow(cst("Program"), cst("LifetimeAnnotation"))
}
pub fn data_dependence_ty() -> Expr {
arrow(cst("Stmt"), arrow(cst("Stmt"), prop()))
}
pub fn control_dependence_ty() -> Expr {
arrow(cst("Stmt"), arrow(cst("Stmt"), prop()))
}
pub fn program_dependence_graph_ty() -> Expr {
arrow(cst("Program"), cst("PDG"))
}
pub fn backward_slice_ty() -> Expr {
arrow(
cst("PDG"),
arrow(cst("SliceCriterion"), set_ty(cst("Stmt"))),
)
}
pub fn forward_slice_ty() -> Expr {
arrow(
cst("PDG"),
arrow(cst("SliceCriterion"), set_ty(cst("Stmt"))),
)
}
pub fn slice_correct_ty() -> Expr {
pi(
BinderInfo::Default,
"prog",
cst("Program"),
pi(
BinderInfo::Default,
"c",
cst("SliceCriterion"),
app(
cst("PreservesSemantics"),
app2(
cst("BackwardSlice"),
app(cst("ProgramDependenceGraph"), bvar(1)),
bvar(0),
),
),
),
)
}
pub fn build_static_analysis_env() -> Environment {
let mut env = Environment::new();
let axioms: &[(&str, Expr)] = &[
("Lattice", lattice_ty()),
("LatticeBottom", lattice_bottom_ty()),
("LatticeTop", lattice_top_ty()),
("LatticeJoin", lattice_join_ty()),
("LatticeMeet", lattice_meet_ty()),
("LatticeLeq", lattice_leq_ty()),
("MooreFamily", moore_family_ty()),
("CompleteLattice_GaloisConn", complete_lattice_galois_ty()),
("ConcreteSemantics", concrete_semantics_ty()),
("AbstractSemantics", abstract_semantics_ty()),
("GaloisConnection", galois_connection_ty()),
("Abstraction", abstraction_ty()),
("Concretization", concretization_ty()),
("GaloisInsertion", galois_insertion_ty()),
("Widening", widening_ty()),
("Narrowing", narrowing_ty()),
("Widening_Terminates", widening_terminates_ty()),
("AbstractInterp_Sound", abstract_interp_sound_ty()),
("Narrowing_RefinesPost", narrowing_refines_post_ty()),
("HeapGraph", heap_graph_ty()),
("HeapNode", heap_node_ty()),
("SharingPred", sharing_pred_ty()),
("CyclicPred", cyclic_pred_ty()),
("ShapeDescriptor", shape_descriptor_ty()),
("shape_join", shape_join_ty()),
("shape_transfer", shape_transfer_ty()),
("ShapeSound", shape_sound_ty()),
("ThreeValued", three_valued_ty()),
("MustAlias", must_alias_ty()),
("AllocSite", alloc_site_ty()),
("PointsTo", points_to_ty()),
("AndersenAnalysis", andersen_analysis_ty()),
("SteensgaardAnalysis", steensgaard_analysis_ty()),
("Andersen_Sound", andersen_sound_ty()),
("Steensgaard_SubAndersen", steensgaard_sub_andersen_ty()),
("Andersen_Cubic", andersen_cubic_ty()),
("Steensgaard_AlmostLinear", steensgaard_almost_linear_ty()),
("AliasResult", alias_result_ty()),
("MayAlias", may_alias_ty()),
("MustAliasPair", must_alias_pair_ty()),
("TypeBasedAlias", type_based_alias_ty()),
("NoAlias", no_alias_ty()),
("Alias_Undecidable", alias_undecidable_ty()),
("SoftType", soft_type_ty()),
("SoftTypeCheck", soft_type_check_ty()),
("RefinementType", refinement_type_ty()),
("EffectType", effect_type_ty()),
("EffectSubtype", effect_subtype_ty()),
("Liquid_Haskell_Sound", liquid_haskell_sound_ty()),
("CallSite", call_site_ty()),
("AbstractClosure", abstract_closure_ty()),
("ZeroCFA", zero_cfa_ty()),
("KCFA", k_cfa_ty()),
("CFA_Overapprox", cfa_overapprox_ty()),
("CFA_Monotone_in_k", cfa_monotone_k_ty()),
("KCFA_Complexity", k_cfa_complexity_ty()),
("Effect", effect_ty()),
("EffectSet", effect_set_ty()),
("ReadEffect", read_effect_ty()),
("WriteEffect", write_effect_ty()),
("ExnEffect", exn_effect_ty()),
("infer_effects", infer_effects_ty()),
("EffectSound", effect_sound_ty()),
("PureFunction", pure_function_ty()),
("ResourceType", resource_type_ty()),
("UsageAnnotation", usage_annotation_ty()),
("LinearType", linear_type_ty()),
("AffineType", affine_type_ty()),
("ResourceUsageAnalysis", resource_usage_analysis_ty()),
("LeakFreedom", leak_freedom_ty()),
("LinearType_LeakFree", linear_type_leak_free_ty()),
("UsageCount_Sound", usage_count_sound_ty()),
("Thread", thread_ty()),
("LockSet", lock_set_ty()),
("HappensBefore", happens_before_ty()),
("DataRace", data_race_ty()),
("EraserLockSet", eraser_lock_set_ty()),
("Eraser_Invariant", eraser_invariant_ty()),
("TSan_Sound", tsan_sound_ty()),
("DataRaceFreedom", data_race_freedom_ty()),
("DRF_Sequential", drf_sequential_ty()),
("TaintSource", taint_source_ty()),
("TaintSink", taint_sink_ty()),
("Sanitizer", sanitizer_ty()),
("TaintLabel", taint_label_ty()),
("TaintPropagation", taint_propagation_ty()),
("TaintViolation", taint_violation_ty()),
("Taint_Sound", taint_sound_ty()),
("Taint_NoFalseNegatives", taint_no_false_neg_ty()),
("SepLogicHeap", sep_logic_heap_ty()),
("SepConj", sep_conj_ty()),
("SepImp", sep_imp_ty()),
("PointsToCell", points_to_cell_ty()),
("FrameRule", frame_rule_ty()),
("HeapShape_TreePred", heap_shape_tree_pred_ty()),
("MemorySafety", memory_safety_ty()),
("OwnershipTransfer", ownership_transfer_ty()),
("Typestate", typestate_ty()),
("TypestateProtocol", typestate_protocol_ty()),
("TypestateTransition", typestate_transition_ty()),
("TypestateCheck", typestate_check_ty()),
("MustUseResource", must_use_resource_ty()),
("TypestateSound", typestate_sound_ty()),
("Region", region_ty()),
("RegionAnnotation", region_annotation_ty()),
("EscapeAnalysis", escape_analysis_ty()),
("RegionInference", region_inference_ty()),
("Escape_Sound", escape_sound_ty()),
("RegionSubtyping", region_subtyping_ty()),
("MonadicEffect", monadic_effect_ty()),
("GradedMonad", graded_monad_ty()),
("CapabilitySet", capability_set_ty()),
("CapabilityJudgment", capability_judgment_ty()),
("EffectPolymorphism", effect_polymorphism_ty()),
("AlgebraicEffectHandler", algebraic_effect_handler_ty()),
("GradualType", gradual_type_ty()),
("UnknownType", unknown_type_ty()),
("ConsistencyRel", consistency_rel_ty()),
("CastInsertion", cast_insertion_ty()),
("CastCorrectness", cast_correctness_ty()),
("Blame_Theorem", blame_theorem_ty()),
("LiquidType", liquid_type_ty()),
("QualifierInstantiation", qualifier_instantiation_ty()),
("SubtypingRefinement", subtyping_refinement_ty()),
("RefinementInference", refinement_inference_ty()),
("LiquidType_Complete", liquid_type_complete_ty()),
("SecurityLabel", security_label_ty()),
("SecrecyLattice", secrecy_lattice_ty()),
("LabelEnv", label_env_ty()),
("NonInterference", non_interference_ty()),
("Declassification", declassification_ty()),
("IFCTypeSystem", ifc_type_system_ty()),
("NI_Theorem", ni_theorem_ty()),
("ConstantFolding", constant_folding_ty()),
("ConstantPropagation", constant_propagation_ty()),
("ConstFold_Correct", const_fold_correct_ty()),
("IntervalDomain", interval_domain_ty()),
("BitfieldDomain", bitfield_domain_ty()),
("ValueRangeAnalysis", value_range_analysis_ty()),
("VRA_Sound", vra_sound_ty()),
("NullabilityAnnotation", nullability_annotation_ty()),
("NullPointerAnalysis", null_pointer_analysis_ty()),
("DefiniteAssignment", definite_assignment_ty()),
("NullSafety", null_safety_ty()),
("NullAnalysis_Sound", null_analysis_sound_ty()),
("LockOrder", lock_order_ty()),
("DeadlockFreedom", deadlock_freedom_ty()),
("LockOrder_Acyclic", lock_order_acyclic_ty()),
("AtomicBlock", atomic_block_ty()),
("Atomicity_Serializability", atomicity_serializability_ty()),
("LockSetAnalysis", lock_set_analysis_ty()),
("OwnershipType", ownership_type_ty()),
("BorrowKind", borrow_kind_ty()),
("Lifetime", lifetime_ty()),
("BorrowCheck", borrow_check_ty()),
("OwnershipUnique", ownership_unique_ty()),
("BorrowCheck_MemSafe", borrow_check_mem_safe_ty()),
("LifetimeSubtyping", lifetime_subtyping_ty()),
("NonLexicalLifetime", non_lexical_lifetime_ty()),
("DataDependence", data_dependence_ty()),
("ControlDependence", control_dependence_ty()),
("ProgramDependenceGraph", program_dependence_graph_ty()),
("BackwardSlice", backward_slice_ty()),
("ForwardSlice", forward_slice_ty()),
("Slice_Correct", slice_correct_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
env
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_env_nonempty() {
let env = build_static_analysis_env();
let names = [
"Lattice",
"GaloisConnection",
"Widening",
"Narrowing",
"AndersenAnalysis",
"HappensBefore",
"TaintPropagation",
"ShapeDescriptor",
"KCFA",
"DataRaceFreedom",
];
let count = names
.iter()
.filter(|&&n| env.get(&Name::str(n)).is_some())
.count();
assert_eq!(count, 10);
}
#[test]
fn test_interval_lattice() {
let a = Interval::Range(1, 5);
let b = Interval::Range(3, 8);
assert_eq!(a.join(&b), Interval::Range(1, 8));
assert_eq!(a.meet(&b), Interval::Range(3, 5));
assert!(Interval::Bottom.leq(&a));
assert!(a.leq(&Interval::top()));
assert!(!b.leq(&a));
}
#[test]
fn test_interval_widening() {
let mut x = Interval::Range(0, 0);
for _ in 0..5 {
let next = x.add(&Interval::single(1));
x = x.widen(&next);
}
assert_eq!(x, Interval::Range(0, i64::MAX));
}
#[test]
fn test_sign_domain() {
assert_eq!(Sign::of(3), Sign::Pos);
assert_eq!(Sign::of(-2), Sign::Neg);
assert_eq!(Sign::of(0), Sign::Zero);
assert_eq!(Sign::Pos.join(&Sign::Neg), Sign::Top);
assert_eq!(Sign::Pos.add(&Sign::Zero), Sign::Pos);
assert_eq!(Sign::Neg.neg(), Sign::Pos);
}
#[test]
fn test_andersen_copy_chain() {
let mut pta = AndersenPTA::new(3);
pta.add_alloc(0, 0);
pta.add_copy(0, 1);
pta.add_copy(1, 2);
pta.solve();
assert!(pta.pts[0].contains(&0));
assert!(pta.pts[1].contains(&0));
assert!(pta.pts[2].contains(&0));
assert!(pta.may_alias(0, 1));
assert!(pta.may_alias(1, 2));
}
#[test]
fn test_taint_propagation() {
let mut ts = TaintState::new();
ts.add_source("user_input");
ts.propagate("x", &["user_input"]);
ts.propagate("y", &["x", "const"]);
assert!(ts.violates("x"));
assert!(ts.violates("y"));
ts.sanitize("x");
assert!(!ts.violates("x"));
assert!(ts.violates("y"));
}
#[test]
fn test_eraser_race_detected() {
let mut state = EraserState::new();
let locks_t1: BTreeSet<usize> = vec![1].into_iter().collect();
let locks_t2: BTreeSet<usize> = vec![2].into_iter().collect();
state.observe_access(0, &locks_t1, true);
state.observe_access(1, &locks_t2, true);
assert!(state.has_race());
}
#[test]
fn test_eraser_no_race() {
let mut state = EraserState::new();
let locks: BTreeSet<usize> = vec![42].into_iter().collect();
state.observe_access(0, &locks, true);
state.observe_access(1, &locks, false);
assert!(!state.has_race());
}
#[test]
fn test_fixpoint_reachability() {
let edges = vec![vec![1], vec![2], vec![]];
let mut solver = FixpointSolver::new(
3,
edges,
false,
|a: &bool, b: &bool| *a || *b,
|n, v| if n == 0 { true } else { *v },
);
solver.values[0] = true;
solver.solve();
assert!(solver.values[1]);
assert!(solver.values[2]);
}
#[test]
fn test_new_axioms_registered() {
let env = build_static_analysis_env();
let names = [
"SepConj",
"FrameRule",
"TypestateSound",
"EscapeAnalysis",
"GradedMonad",
"CastCorrectness",
"LiquidType",
"NonInterference",
"ConstantFolding",
"NullSafety",
"DeadlockFreedom",
"BorrowCheck",
"BackwardSlice",
];
let count = names
.iter()
.filter(|&&n| env.get(&Name::str(n)).is_some())
.count();
assert_eq!(count, names.len());
}
#[test]
fn test_typestate_automaton_file() {
let mut aut = TypestateAutomaton::new(2, 0);
aut.add_transition(0, "open", 1);
aut.add_transition(1, "read", 1);
aut.add_transition(1, "close", 0);
aut.set_accepting(0);
assert!(aut.accepts(&["open", "read", "close"]));
assert!(!aut.accepts(&["open", "read"]));
assert!(aut.violates(&["open", "open"]));
}
#[test]
fn test_ifc_tracker_violation() {
let mut tracker = IFCTracker::new();
tracker.assign("password", SecurityLevel::High);
tracker.assign("user_id", SecurityLevel::Low);
tracker.propagate("derived", &["password", "user_id"]);
assert_eq!(tracker.label_of("derived"), SecurityLevel::High);
tracker.check_flow("derived", &SecurityLevel::Low);
assert!(tracker.has_violation());
}
#[test]
fn test_ifc_tracker_ok() {
let mut tracker = IFCTracker::new();
tracker.assign("public_id", SecurityLevel::Low);
tracker.check_flow("public_id", &SecurityLevel::High);
assert!(!tracker.has_violation());
}
#[test]
fn test_const_prop_state() {
let mut s1 = ConstPropState::new();
s1.set_const("x", 10);
s1.set_const("y", 5);
assert_eq!(s1.fold_add("x", "y"), Some(15));
let mut s2 = ConstPropState::new();
s2.set_const("x", 10);
s2.set_top("y");
let joined = s1.join(&s2);
assert_eq!(joined.get("x"), Some(10));
assert_eq!(joined.get("y"), None);
}
#[test]
fn test_pd_graph_slicing() {
let mut pdg = PDGraph::new(4);
pdg.add_data_edge(0, 1);
pdg.add_data_edge(1, 3);
let bwd = pdg.backward_slice(3);
assert!(bwd.contains(&3));
assert!(bwd.contains(&1));
assert!(bwd.contains(&0));
assert!(!bwd.contains(&2));
let fwd = pdg.forward_slice(0);
assert!(fwd.contains(&0));
assert!(fwd.contains(&1));
assert!(fwd.contains(&3));
}
#[test]
fn test_null_tracker_alarm() {
let mut tracker = NullTracker::new();
tracker.declare_maybe_null("ptr");
tracker.dereference("ptr");
assert!(tracker.has_alarm());
}
#[test]
fn test_null_tracker_no_alarm() {
let mut tracker = NullTracker::new();
tracker.declare_non_null("safe_ptr");
tracker.dereference("safe_ptr");
assert!(!tracker.has_alarm());
}
#[test]
fn test_null_tracker_join() {
let mut t1 = NullTracker::new();
t1.declare_non_null("p");
let mut t2 = NullTracker::new();
t2.declare_null("p");
let merged = t1.join(&t2);
assert_eq!(merged.get("p"), &Nullability::MaybeNull);
}
}