How the Frml Verifier Works¶
This tutorial walks through the Frml verification engine, explaining how a Frml program becomes Boolean logic that the Z3 solver can check, and what Z3 does with that logic. The verifier and tutorial are layered:
scalarhandles straight-line and branching code (no functions or loops).contractsadds contracts and function calls.loopaddswhileloops.arrayadds fixed-size arrays.builtinadds built-in functions to do I/O andpush/poparray values.completehandles the full language.
Who this is for¶
- You are an experienced programmer.
- You understand basic Boolean logic (
and,or,not, implication). - You have no prior background in formal verification.
- You already know what a lexer, parser, and abstract syntax tree (AST) are.
What you will learn¶
- What a verification condition is.
- How contracts, loops, arrays, calls, and quantifiers become Z3 formulas.
The files that matter¶
frml/typechecker_XYZ.pydoes type checking at theXYZlevel.frml/prover_XYZ.pyverifies programs at theXYZlevel.
The rest of frml/*.py parses and runs programs.
The big picture¶
- The lexer and parser turn program text into an AST.
- The typechecker rejects programs with type errors.
- The prover turns the AST into verification conditions of the form:
- The prover asks Z3 to confirm every verification condition.
- If Z3 confirms all of them, the program is verified.
What a verifier does¶
- A proof obligation is a claim:
- Symbolically:
h1 ... hnare facts known at some point in the program.goalis a fact that must hold at that point.- Example claims from a real program:
- "knowing
x >= 0, prove0 <= x" - "knowing
i < n, provei + 1 <= n" - "knowing nothing, prove
x > x" (this one is false)
- "knowing
- The prover's job is to produce claims in this shape.
What Z3 is and what it does¶
- Z3 is an SMT solver.
- SMT = Satisfiability Modulo Theories.
- Z3 knows the theory of integers, arrays, strings, and Boolean logic.
- A formula is satisfiable when some assignment of values to its variables makes it true.
- Given a formula, Z3 returns one of three answers:
sat: a satisfying assignment exists and Z3 can show you one.unsat: no satisfying assignment exists.unknown: Z3 gave up or timed out.
- An example that can be safisfied:
- An example that cannot:
From "is it valid?" to "is it unsatisfiable?"¶
- The prover wants to prove that
hypotheses => goalis valid.- Where "valid" means "true for every possible assignment of the variables".
- Z3 does not directly check validity: it checks satisfiability.
- The two are connected:
A => Bis valid exactly whennot (A => B)is unsatisfiable. - So the prover asks Z3:
- If Z3 says
unsat, then no counterexample exists, so the goal is proved. - If Z3 says
sat, it found a counterexample, so the goal is false. - If Z3 says
unknown, the proof is inconclusive. - That's the entire proof mechanism: everything else is just building the
hypotheses and goals.
- For a rather large value of "just".
Using Z3 in Python¶
A,B, andCdon't have specific values.- Instead, each represents the set of possible Boolean values.
- We can then specify constraints like
A == B.
- And then ask Z3 to find a model that satisfies those constraints:
An example of unsatisfiability¶
- Require
Ato equalBandBto equalCbutAandCto be unequal