Danger Invariants
Overview
Danger invariants provide a dual approach to traditional safety invariants. While safety invariants prove that a program is safe (no bad states are reachable), danger invariants prove that a program is unsafe (bad states are reachable). This is particularly useful for bug finding and unsafety verification.
A danger invariant D(x) together with a ranking function R(x) forms an unsafety witness that proves the existence of a reachable bad state.
Verification Conditions
For a danger invariant D(x) and ranking function R(x), the following conditions must hold:
Base / Reachability:
\[\exists x. \text{Init}(x) \wedge D(x)\]The danger invariant must be reachable from an initial state.
Progress:
\[\forall x. D(x) \wedge G(x) \wedge \text{Post}(x) \Rightarrow \exists x'. \text{Trans}(x,x') \wedge D(x') \wedge R(x') < R(x)\]From any state satisfying the danger invariant, there must exist a transition to another state in the danger invariant with a strictly decreasing ranking function.
Additionally, the ranking function must be positive:
\[\forall x. D(x) \Rightarrow R(x) > 0\]Exit-Violation (when a guard G is provided):
\[\forall x. D(x) \wedge \neg G(x) \Rightarrow \neg \text{Post}(x)\]When exiting the loop (guard is false), the safety property must be violated.
Result Interpretation
The danger invariant prover returns a VerificationResult with the following semantics:
is_safe = True: The provided witness is invalid (no bug proved)
is_safe = False: The witness is valid (bug proved)
is_unknown = True: The solver answered unknown, or the witness was rejected but no safety proof has been given
Usage
The danger invariant prover is primarily used programmatically:
from aria.efmc.engines.danger import DangerInvariantProver
from aria.efmc.sts import TransitionSystem
import z3
# Create transition system
sts = TransitionSystem(...)
# Create prover
prover = DangerInvariantProver(sts)
# Define danger invariant and ranking function
x = sts.variables[0]
danger_inv = x > 100 # Example danger invariant
ranking_func = 200 - x # Example ranking function
guard = x < 200 # Optional loop guard
# Verify the danger invariant
result = prover.verify(
inv=danger_inv,
rank=ranking_func,
guard=guard,
require_rank_positive=True,
solver_timeout_ms=60000
)
if not result.is_safe:
print("Bug proved! Unsafety witness is valid.")
print(f"Danger invariant: {danger_inv}")
print(f"Ranking function: {ranking_func}")
else:
print("Witness rejected or unknown")
API Reference
DangerInvariantProver.verify()
Parameters:
- inv: The danger invariant formula (z3.ExprRef)
- rank: The ranking function formula (z3.ExprRef)
- guard: Optional loop guard formula (z3.ExprRef, default: None)
- require_rank_positive: Whether to require ranking function to be positive (bool, default: True)
- solver_timeout_ms: Solver timeout in milliseconds (int, default: None)
Returns:
- VerificationResult with the verification outcome
Bit-Vector Support
The danger invariant prover supports both signed and unsigned bit-vector interpretations:
For signed bit-vectors: Uses signed comparison (
>)For unsigned bit-vectors: Uses unsigned comparison (
UGT)
The signedness is determined from the transition system’s configuration.
Example: Proving Unsafety
Consider a program that increments a counter until it overflows:
# Transition system where x starts at 0 and increments
# Safety property: x < 256
# We want to prove this is violated
x = z3.BitVec('x', 8)
x_p = z3.BitVec('x_p', 8)
# Danger invariant: x >= 255 (close to overflow)
danger_inv = z3.UGE(x, 255)
# Ranking function: 256 - x (decreases as x increases)
ranking_func = 256 - x
# Guard: x < 256 (loop continues)
guard = z3.ULT(x, 256)
prover = DangerInvariantProver(sts)
result = prover.verify(danger_inv, ranking_func, guard=guard)
# If result.is_safe is False, we've proved the program is unsafe
Applications
Bug Finding: Prove that certain error states are reachable
Counterexample Generation: Generate concrete paths to buggy states
Refinement: Use danger invariants to guide abstraction refinement
Dual Verification: Complement safety verification with unsafety proofs