There are various approaches to prove the correctness of a program:
satisfiability-based: bounded executions and errors of P are encoded as a formulae Exec(P) and Err, respectively.
If no bounded execution violates the assertion, then: ⊢Exec(P)⟹¬Err. Solvers prove this by showing Exec(P)∧Err unsatisfiable.
model checking: check whether program P is a model of formula ¬Err: P⊨¬Err
automata-theoretic: the executions of program P are words accepted by automaton AP, erroneous executions are words accepted by AErr. Program
P contains no assertion violation if L(AP×AErr)=∅
lattice-theoretic: originated from programming language semantics and compiler construction, relies on abstract interpretation to interpret program P and assertion Err in a lattice A of approximation.
The program is error-free if the lattice element denoted by P is separate from the lattice element denoted by the error: [[P]]A⊓[[Err]]A⊑⊥
One can move in between these representations: