1 / 38

Decidable Verification of Uninterpreted Programs

Decidable Verification of Uninterpreted Programs. Umang Mathur. P. Madhusudan. Mahesh Viswanathan. Program Verification. In general, verification over infinite domains is undecidable Requires manual effort - contracts, loop invariants. Existing Decidable Classes. Unnatural program models.

huseby
Download Presentation

Decidable Verification of Uninterpreted Programs

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Decidable Verification of Uninterpreted Programs Umang Mathur P. Madhusudan Mahesh Viswanathan

  2. Program Verification • In general, verification over infinite domains is undecidable • Requires manual effort - contracts, loop invariants Existing Decidable Classes Unnatural program models Finite domain (Boolean programs) Undecidable

  3. Uninterpreted Programs • Programs with constants, functions and predicates that are completely uninterpreted • Interpretations are given by data model • Satisfies a post-condition φ if φ holds in all data models

  4. Contributions • Verification of uninterpreted programs is undecidable • Coherent and k-Coherent programs – Admit Decidable Verification First class of programs with infinite domain to admit decidable verification Decidable with recursive function calls Maximally decidable - simple extensions become undecidable PSPACE without recursion EXPTIME with recursion

  5. Uninterpreted Programs • <prog> := <stmt><post-condition> <stmt> := x ← y x ← f(z1, z2, …, zk) if<cond> then<stmt>else<stmt> while<cond><stmt> • skip • assume(<cond>) <stmt>;<stmt> <cond> := x= y • R(z1, z2, …, zk) ¬<cond> <cond> ∨ <cond> Program Syntax • <post-condition>:= x= y • R(z1, z2, …, zk) • ¬<post-condition> • <post-condition>∨<post-condition> Post-conditions

  6. Uninterpreted Programs Verification (P ⊨ φ) • P ⊨ φ, if • for every data model M (interpretation for constants, functions and relations in P), and • for every execution ρ of P that is feasible in M, • φholds in M at the end of ρ

  7. Uninterpreted Programs b ← F; while(x ≠ y){if(key(x) = k)then{ b ← T; r ← x;} x ← n(x);} @post:b=T ⇒ key(r)=k Check if • for all interpretations of n and key, • and for all initial values of x, y, b, r and k the following formula holds at the end of each executionb=T ⇒ key(r)=k This is a coherent program and we can verify it without loop invariants ! Search key k in list segment from x to y

  8. Algebraic View of Program Executions • Sequence of basic statements • x← y • x← f(z1, z2, …, zk) • assume(x = y) • assume(x≠ y) • Algebraic view of executions: • Compute terms using constants and function symbols • Accumulate assumptions involving terms

  9. Algebraic View of Program Executions • Sequence of basic statements • x← y • x← f(z1, z2, …, zk) • assume(x = y) • assume(x≠ y) • Algebraic view of executions: • Compute terms using constants and function symbols • Accumulate assumptions involving terms

  10. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} Assumptions Terms

  11. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • b0 • T0 • y0 • k0 • d0 • x0 • F0 • b • T • x • y • d • F • k Assumptions Terms

  12. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 • T0 • F0 • d0 • k0 • b0 • y0 • x • d • y • F • T • b • k Assumptions Terms

  13. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • T0 • y0 • F0 • k0 • x0 • b0 • d0 • k • T • F • x • d • b • y Assumptions Terms

  14. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • d0 • y0 • F0 • x0 • b0 • k0 • T0 • y • x • d • F • T • b • k Assumptions Terms

  15. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • x0 • T0 • F0 • d0 • b0 • k0 • y0 • key(x0) • x • F • T • b • y • k • d Assumptions Terms

  16. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • x0 • T0 • F0 • d0 • b0 • k0 • y0 • key(x0) • key(x0) ≠ k0 • d • x • F • T • b • y • k Assumptions Terms

  17. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;}x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • n(x0) • x0 • d0 • b0 • F0 • T0 • k0 • y0 • key(x0) • key(x0) ≠ k0 • x • T • b • y • k • d • F Assumptions Terms

  18. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • n(x0) • x0 • y0 • F0 • d0 • b0 • k0 • T0 • key(x0) • key(x0) ≠ k0 • n(x0) ≠ y0 • F • T • b • y • k • d • x Assumptions Terms

  19. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • key(n(x0)) • n(x0) • x0 • d0 • b0 • F0 • T0 • k0 • y0 • key(x0) • key(x0) ≠ k0 • n(x0) ≠ y0 • F • T • b • y • k • x • d Assumptions Terms

  20. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • key(n(x0)) • n(x0) • x0 • y0 • F0 • d0 • b0 • k0 • T0 • key(x0) • key(x0) ≠ k0 • n(x0) ≠ y0 • key(n(x0)) = k0 • F • T • b • y • k • x • d Assumptions Terms

  21. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{b ← T;} x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • key(n(x0)) • n(x0) • x0 • T0 • F0 • d0 • b0 • k0 • y0 • key(x0) • key(x0) ≠ k0 • n(x0) ≠ y0 • key(n(x0)) = k0 • F • T • y • k • x • d • b Assumptions Terms

  22. Algebraic View of Program Executions assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;}x ← n(x);} • T0 ≠ F0 • x0 ≠ y0 • key(n(x0)) • n(n(x0)) • n(x0) • x0 • d0 • b0 • F0 • T0 • k0 • y0 • key(x0) • key(x0) ≠ k0 • n(x0) ≠ y0 • key(n(x0)) = k0 • F • T • y • k • d • b • x Assumptions Terms

  23. Coherence A program execution is coherent if it is memoizing, and has early assumes Coherence Memoizing Early Assumes = +

  24. Coherence Memoizing Don’t recompute terms.If a term is recomputed, it must already be present in some variable • Make equality assumptions early. • Make equality assumptions between terms before forgetting a computed superterm Early Assumes

  25. Coherence • If a term is recomputed, then it must already be present in some variable • Let 𝞼 · ”x ← f(y)” be an execution such that t = f(y)was computed earlier in 𝞼. • Then some program variable z must store t after 𝞼. Memoizing d d

  26. Coherence • If a term is recomputed, then it must already be present in some variable • Let 𝞼 · ”x ← f(y)” be an execution such that t = f(y)or some t’~t was computed earlier in 𝞼. • Then some program variable z must store t or some t”~t after 𝞼. Memoizing d Equivalent according the assumptions seen so far in 𝞼 d

  27. Coherence All executions of this program are memoizing Memoizing assume(T ≠ F) b ← F; while(x ≠ y){ d ← key(x);if(d = k)then{ b ← T;} x ← n(x);}

  28. Coherence Memoizing Don’t recompute terms.If a term is recomputed, it must already be present in some variable • Make equality assumptions early. • Make equality assumptions between terms before forgetting a computed superterm Early Assumes

  29. Coherence • If two terms are assumed to be equal, make the assumption early • Let 𝞼 · ”assume(x = y)” be an execution. If s, a superterm of the term stored in either x or y (modulo ~)has been computed in 𝞼, • then some program variable z must store a term equivalent to s at the end of 𝞼. Early Assumes

  30. Verification of Coherent Programs A program is coherent if all its executions are coherent Verification of coherent programs is decidable • PSPACE-complete for coherent programs without recursion • EXPTIME-complete for recursive coherent programs First class of infinite domain programs to admit decidable verification Maximally decidable – relaxing either memoizing or early assumes leads to undecidability

  31. Verification of Coherent Programs Key Idea Streaming Congruence Closure

  32. Streaming Congruence Closure • Constant memory streaming algorithm for analyzing executions • Maintain congruence closure of the set of terms corresponding only to current values of the program variables • Coherence makes such an algorithm possible • Bounded Path decomposition

  33. Streaming Congruence Closure • Automaton A for streaming congruence closure accepting executions not satisfying postcondition φ • States of A are(~, d, P) Functional relationship between variables Equalities between variables Dis-equalities between variables x = y b= f(a) x ≠ w

  34. Streaming Congruence Closure • P ⊨ φ if and only if Executions(P) ∩ L(A) = ∅ • For while programs, both Executions(P) and L(A) are regular - decidable. • For recursive programs, both Executions(P) and L(A) are visibly pushdown languages - decidable.

  35. Verification of Coherent Programs A program is coherent if all its executions are coherent Verification of coherent programs is decidable • PSPACE-complete for coherent programs without recursion • EXPTIME-complete for recursive coherent programs Checking if a program is coherent is also decidable

  36. k-Coherence assume(x ≠ NIL); y ← n(x); assume(y ≠ NIL); y ← n(y); while(y ≠ NIL){ x ← n(x); y ← n(y);} assume(x ≠ NIL); y ← n(x); g ← y; assume(y ≠ NIL); y ← n(y); while(y ≠ NIL){ x ← n(x); g ← y; y ← n(y);} Add 1 ghost variable 1-coherent Non-coherent Coherent

  37. k-Coherence A program isk-coherent if it can be made coherent by adding k ∈ ℕ extra (write-only) ghost variables. Given k ∈ ℕ, • theproblem of checking if P is k-coherentprogram is decidable in PSPACE • verification of k-coherent programs is PSPACE-complete (EXPTIME-complete with recursion)

  38. Concluding Remarks Summary Future Work • Evaluation as a program verifier (see EUForia, VMCAI’19) • Theories and axioms • Trace abstraction [Heizmann et al] • Coherent and k-Coherent programs • Completely automatic verification • First natural decidable class over infinite domain • Efficiently decidable • PSPACE for non-recursive • EXPTIME for recursive • Checking coherence and k-coherence is decidable

More Related