290 likes | 299 Views
This tutorial provides an introduction to program verification and explores the fundamental differences between for-loops and while-loops. It also discusses the connection with simple recursion and demonstrates how to transform a for-loop to a while-loop. The consequences for calculating a weakest precondition are compared in scenarios using symbolic execution and formal verification.
E N D
CSE 3341.03 Winter 2008Introduction to Program Verification for-loops; review
Sec. 9.9 • fundamental differences between for-loops and while-loops? • why not do everything with while-loops? • what's the connection with simple recursion?
transforming for-loop to a while-loop • for (int V = Initial; V < Limit; V++) S; translates to: int V = Initial; while(V < Limit ) {S ; V++;} • need to add an invariant. • assume if loop is entered it exits with V = Limit (no break; Limit unmodified) What is the consequence for calculating a wp?
compare scenarios: symbex vs. wp • symbex: • title: verify a code segment (assignment, conditional, procedure statements) • context (what's given?) • proof obligations? • background? correctness of simplification rules, Well-Behaved Expression assumption
wp scenario, p. 53 • title: verify a code fragment (any statement for which wp(S, Q) or pre(S, Q) is implemented) • context: optional pre-condition, code-segment and a goal or desired post-condition; propose an invariant for each loop statement • proof obligations: ?
exam: closed book, two hours • exam: closed book, two hours April 10, 7 PM, Chemistry Building 120
Father Sarducci: http://www.cs.washington.edu//info/videos/asx/5minuteU.asx • see link on the Extras page: http://www.cse.yorku.ca/course_archive/2007-08/W/3341/extras.html
Software verification: "Sarducci" version Introductory: verification is spell-checking for program logic. Advanced: “functional good; procedural bad”.
Ch. 0 • programming errors can be disastrous • testing isn’t good enough • if we’re serious about programming quality, we will need formal verification methods • tedious (lots of intricate detail) • hard to do correctly • solution? automation -- hence verification tools
Ch. 1 • propositional calculus is fundamental why do we replace logical symbols with English words? enables automated calculation of boolean expressions • classification of propositions: • tautology, satisfiable, contingent, contradiction why is this of interest?
Ch. 2 (tautology) • we can automate the testing whether a proposition is a tautology using the method of a truth table: • requires possibly exhaustive search -- of what? • biased towards detecting falsity • automating the truth-table method just requires entering rules for all the logical operators allowed in the calculus
rule-based programming • control structure is weak or non-existent • structure of the data selects the rule which tests it • iteration replaced by recursion
do we need anything else besides tautology-checking to classify props? • can use tautology-checking to check for contingency or contradiction • nice feature of the calculation: if not a tautology, we get a counter-example
Ch. 3 (wang) • different data structure gives a more useful algorithm • what is the datastructure? • wang biased towards truth • allows complex descriptions, using terms • term is a very versatile data structure for representing math. concepts, i. e. for symbolic computation • in what sense, is wang a syntactic method as opposed to the truth-table’s semantic method? • how is proof different from implication?
sequents • wang implements tautology-checking by converting the input to a sequent: • {conjunction} >> {disjunction} • using special rules to reduce the input to sets of non-logical terms
terms • Lisp implements terms as lists • advantage: functor can be a variable • (2nd order logic) • disadvantage: pattern-matching is more complex • Prolog implements lists as terms • advantage: very good fit with pattern-matching
Ch. 4 (simplify) • add math. knowledge in form of rewrite or simplification rules theories = collections of inter-related rules • use canonical forms to recognize identities syntactically • use pattern-variables and rewriting to capture semantic relationships e. g. X = X ->> true.
pattern variables • Note: pattern variables act like universally quantified variables • allows us to extend prop. calculus to FOL or predicate calculus • example: (x) P(x). can be written as p(X) ->> true.
Ch. 5 (prover, induction) • use simplification to evaluate symbolic expressions involving functions on ADTs • verify propositions about ADTs by combining tautology checking and simplification = prover (what else does prover add?) • in general, computable functions are recursively definable on a domain of ADTs; for some recursive definitions (we called them simple recursion) we can use induction to verify that the recursive definition is correct relative to another non-recursive definition
recursive definition describes how the function would be computed in a functional programming language • the non-recursive definition is usually an algebraic expression.
mathematical induction • the proof that a recursive function is correctly defined rests on the principle of induction a rule of inference: given a premise (proposition) infer another proposition • e. g. P(0) and (0 < n and P(n-1) implies P(n) |- P(n).
extensions from simple recursionto tail-recursion • verification by transformation • what’s the advantage? • for-loops transform easily into tail-recursion • (Ch. 9: for-loops transform into restricted while-loops)
from integers to recursive ADTs • key idea: to use induction to prove things about an ADT, we need, given an initial object, to be able to compute a smaller object . . • and by repeating this recursively, we get to the base (non-recursive) case • key idea: any verification scenario determines a set of proof-obligations to be discharged: either by calculation or by a “manual” proof. • tools assist in organizing this process and determining whether enough theory is provided to complete the proofs
scenarios • many types of verifications • key idea: any verification scenario determines a specific set of proof-obligations to be discharged: either by calculation or by a “manual” proof. • tools assist in organizing this process and determining whether enough mathematical theory and definitions are provided to complete the proofs
Ch. 6 • varieties of verification • implementation of one ADT by another (simpler) one. • example: use arrays (non-recursive datatype) to implement stacks or lists. • implementation of a concrete ADT (Circle) as an instance of an abstract one (Shape) • verify that the Circle satisfies the properties of a Shape (how?) • implementation of a complex object as a composition of simple objects • logical circuit
Ch. 7 • specifications are annotations that describe contracts in the form of pre- and post-conditions • we can derive these “by hand” from code, using our informal understanding of what the code is supposed to do • specifications aren’t absolute • they’re relative to somewhat fuzzy background assumptions: that functions are well-behaved (no side effects, etc.); that expressions are assumed to be restricted to values in the domains of the expressions’ functions; that all expressions terminate
Ch. 8 • we can compute post-conditions by symbolic execution (symbex); verify a code segment by showing that the calculated (descriptive) post-condition implies a given goal specification • but disadvantages?
Ch. 9 • assume every code segment has a goal (a purpose) • use wp to verify that the segment achieves the goal, relative to a pre-condition: either true, the post-condition of a previous segment, or a contractual requirement • compute a pre-condition pre(“S;”, Goal), preferably the most general (weakest pre-condition) wp(“S;”) that is guaranteed to achieve the goal • working backwards has advantages; • for loop-free code, wp can be computed using definitions of wp for standard statement types; loops are more complicated • what are the proof-obligations for verifying {P} “while(B) S;” {Goal}?