1 / 35

15-820A Proving Software with PVS

15-820A Proving Software with PVS. Edmund Clarke Daniel Kroening Carnegie Mellon University. Outline. Modeling Software with PVS Complete Example for Sequential Software, including proof The Magic GRIND Modularization. Modeling Software with PVS. int a[10]; unsigned i; int main() {

lars
Télécharger la présentation

15-820A Proving Software with PVS

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. 15-820AProving Software with PVS Edmund Clarke Daniel Kroening Carnegie Mellon University

  2. Outline • Modeling Software with PVS • Complete Example for Sequential Software,including proof • The Magic GRIND • Modularization

  3. Modeling Software with PVS int a[10]; unsigned i; int main() { . . . } 1. Define Type for STATE C: TYPE = [# a: [below(10)->integer], i: nat #] A

  4. Modeling Software with PVS 2. Translate your program into goto program int a[10]; unsigned i,j,k; int main() { L1: i=k=0; L2: if(!(i<10)) goto L4; L3: i++; k+=2; goto L2; L4: j=100; k++; } int a[10]; unsigned i,j,k; int main() { i=k=0; while(i<10) { i++; k+=2; } j=100; k++; } A

  5. Modeling Software with PVS 3. Partition your program into basic blocks 4. Write transition function for each basic block L1(c: C):C= c WITH [i:=0, k:=0] L2(c: C):C= c L3(c: C):C= c WITH [i:=c`i+1, k:=c`k+2] L4(c: C):C= c WITH [j:=100, k:=c`k+1] int a[10]; unsigned i,j,k; int main() { L1: i=k=0; L2: if(!(i<10)) goto L4; L3: i++; k+=2; goto L2; L4: j=100; k++; } A

  6. Modeling Software with PVS 5. Combine transition functions using a program counter PCt: TYPE = { L1, L2, L3, L4, END } int a[10]; unsigned i,j,k; int main() { L1: i=k=0; L2: if(!(i<10)) goto L4; L3: i++; k+=2; goto L2; L4: j=100; k++; } t(c: C): C= CASES c`PC OF L1: L1(c) WITH [PC:=L2], L2: L2(c) WITH [PC:= IF NOT (c`i<10) THEN L4 ELSE L3 ENDIF, L3: L3(c) WITH [PC:=L2], L4: L4(c) WITH [PC:=END], END: c ENDCASES A

  7. Modeling Software with PVS 6. Define Configuration Sequence c(T: nat, initial: C):RECURSIVE C= IF T=0 THEN initial WITH [PC:=L1] ELSE t(c(T-1, initial)) ENDIF MEASURE T 7. Now prove properties about PC=LEND states program_correct: THEOREM FORALL (initial: C): FORALL (T: nat | c(T)`PC=LEND): c(T)`result=correct_result(initial) A

  8. Example I 1. Define Type for STATE bool find_linear(unsigned size, const int a[], int x) { unsigned i; for(i=0; i<size; i++) if(a[i]==x) return TRUE; return FALSE; } C: TYPE = [# size: nat, a: [nat -> integer], x: integer, i: nat, result: bool, PC: PCt #] A

  9. Example II bool find_linear(unsigned size, const int a[], int x) { L1: i=0; L2: if(!(i<size)) goto L8; L3: if(!(a[i]==x)) goto L6; L4: result=TRUE; L5: goto LEND; L6: i++; L7: goto L2; L8: result=FALSE; LEND:; return result; } bool find_linear(unsigned size, const int a[], int x) { unsigned i; for(i=0; i<size; i++) if(a[i]==x) return TRUE; return FALSE; } 2. Translate your program into goto program A

  10. Example III/IV 3. Partition your program into basic blocks 4. Write transition function for each basic block L1(c: C):C=c WITH [i:=0] L2(c: C):C=c L3(c: C):C=c L4(c: C):C=c WITH [result:=TRUE] L5(c: C):C=c L6(c: C):C=c WITH [i:=c`i+1] L7(c: C):C=c L8(c: C):C=c WITH [result:=FALSE] bool find_linear (unsigned size, const int a[], int x) { L1: i=0; L2: if(!(i<size)) goto L8; L3: if(!(a[i]==x)) goto L6; L4: result=TRUE; L5: goto LEND; L6: i++; L7: goto L2; L8: result=FALSE; LEND:; return result; } A

  11. Example V 5. Combine transition functions using a program counter t(c: C):C=CASES c`PC OF L1: L1(c) WITH [PC:=L2], L2: L2(c) WITH[PC:= IF NOT c`i < c`size THEN L8 ELSE L3 ENDIF], L3: L3(c) WITH [PC:= IF NOT c`a(c`i)=c`x THEN L6 ELSE L4 ENDIF], L4: L4(c) WITH [PC:=L5], L5: L5(c) WITH [PC:=LEND], L6: L6(c) WITH [PC:=L7], L7: L7(c) WITH [PC:=L2], L8: L8(c) WITH [PC:=LEND], LEND: c ENDCASES bool find_linear (unsigned size, const int a[], int x) { L1: i=0; L2: if(!(i<size)) goto L8; L3: if(!(a[i]==x)) goto L6; L4: result=TRUE; L5: goto LEND; L6: i++; L7: goto L2; L8: result=FALSE; LEND:; return result; } A

  12. Example VI 6. Define Configuration Sequence c(T: nat, initial: C):RECURSIVE C= IF T=0 THEN initial WITH [PC:=L1] ELSE t(c(T-1, initial)) ENDIF MEASURE T What is the correct result? 7. Now prove properties about PC=LEND states program_correct: THEOREM FORALL (initial: C): FORALL (T: nat | c(T)`PC=LEND): c(T)`result=correct_result(initial) A

  13. Example IV C: TYPE = [# size: nat, a: [nat -> integer], x: integer, i: nat, result: bool, PC: PCt #] correct_result(c: C): bool= EXISTS (j: below(c`size)): c`a(j)=c`x OK!LET’S PROVE THIS! A

  14. Something useful first… C: TYPE = [# size: nat, a: [nat -> integer], x: integer, i: nat, result: bool, PC: PCt #] We need to say: c(T)`a = initial`aÆ c(T)`x = initial`xÆ c(T)`size = initial`size OR: The program only changes i, result, PC program_correct: THEOREM FORALL (initial: C): FORALL (T: nat | c(T)`PC=LEND): c(T)`result=correct_result(initial) This relates initial state and final state A

  15. Something useful first… We need to say: c(T)`a = initial`aÆ c(T)`x = initial`xÆ c(T)`size = initial`size OR: The program only changes i, result, PC invar_constants(T: nat, initial: C): bool= c(T, initial)`size=initial`size AND c(T, initial)`a =initial`a AND c(T, initial)`x =initial`x; constants: LEMMA FORALL (initial:C, T: nat): invar_constants(T, initial) Proof:Induction on T + GRIND next: the real invariant… A

  16. Loop Invariant bool find_linear(unsigned size, const int a[], int x) { unsigned i; for(i=0; i<size; i++) if(a[i]==x) return TRUE; return FALSE; } FORALL (j: below(c`i)): c`a(j)/=c`x A

  17. The Invariant invar(c: C):bool=CASES c`PC OF L1: % i=0; L2: % if(!(i<size)) goto L8; L3: % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: % i++; L7: % goto L2; L8: % result=FALSE; LEND:c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES Beginning of the Loop End of the Loop A

  18. The Invariant What here? invar(c: C):bool=CASES c`PC OF L1: % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: % result=FALSE; LEND:c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES A

  19. The Invariant invar(c: C):bool=CASES c`PC OF L1: TRUE, % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: % result=FALSE; LEND:c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES Exiting the Loop Exiting the Loop A

  20. The Invariant invar(c: C):bool=CASES c`PC OF L1: TRUE, % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: c`i>=c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % result=FALSE; LEND: c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES What here? A

  21. The Invariant invar(c: C):bool=CASES c`PC OF L1: TRUE, % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: c`i<c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: c`i>=c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % result=FALSE; LEND: c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES What here? A

  22. The Invariant invar(c: C):bool=CASES c`PC OF L1: TRUE, % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: c`i<c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(a[i]==x)) goto L6; L4: % result=TRUE; L5: % goto LEND; L6: FORALL (j: below(c`i+1)): c`a(j)/=c`x, % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: c`i>=c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % result=FALSE; LEND: c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES What here? A

  23. The Invariant invar(c: C):bool=CASES c`PC OF L1: TRUE, % i=0; L2: FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(i<size)) goto L8; L3: c`i<c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % if(!(a[i]==x)) goto L6; L4: c`i<c`size AND c`a(c`i)=c`x, % result=TRUE; L5: c`i<c`size AND c`a(c`i)=c`x AND c`result=true, % goto LEND; L6: FORALL (j: below(c`i+1)): c`a(j)/=c`x, % i++; L7: FORALL (j: below(c`i)): c`a(j)/=c`x, % goto L2; L8: c`i>=c`size AND FORALL (j: below(c`i)): c`a(j)/=c`x, % result=FALSE; LEND: c`result <=> EXISTS (j: below(c`size)): c`a(j)=c`x ENDCASES

  24. The Invariant DARING CLAIM “Once you have found the invariant,the proof is done.” We now have the invariant. Lets do the actual proof. Who believes we are done? A

  25. The Gentzen Sequent {-1} i(0)`reset {-2} i(4)`reset |------- {1} i(1)`reset {2} i(2)`reset {3} (c(2)`A AND NOT c(2)`B) Conjunction (Antecedents)  Disjunction (Consequents) Or: Reset in cycles 0, 4 is on, and off in 1, 2.Show that A and not B holds in cycle 2.

  26. The Magic of (GRIND) • Myth: Grind does it all… • Reality: • Use it when: • Case splitting, skolemization, expansion, and trivial instantiations are left • Does not do induction • Does not apply lemmas “... frequently used to automatically complete a proof branch…”

  27. The Magic of (GRIND) • If it goes wrong… • you can get unprovable subgoals • it might expand recursions forever • How to abort? • Hit Ctrl-C twice, then (restore) • How to make it succeed? • Before running (GRIND), remove unnecessary parts of the sequent using (DELETE fnum).It will prevent that GRIND makes wrong instantiations and expands the wrong definitions.

  28. NOW LET’S PROVE THE INVARIANT

  29. A word on automation… • The generation of C, t, and c can be trivially automated • Most of the invariant can be generated automatically – all but the actual loop invariant (case L7/L2) • The proof is automatic unless quantifier instantiation is required A

  30. Modularization t(c: C):C=CASES c`PC OF L1: L1(c) WITH [PC:=L2], L2: L2(c) WITH[PC:= IF NOT c`i < c`size THEN L8 ELSE L3 ENDIF], L3: L3(c) WITH [PC:= IF NOT c`a(c`i)=c`x THEN L6 ELSE L4 ENDIF], L4: L4(c) WITH [PC:=L5], L5: L5(c) WITH [PC:=LEND], L6: L6(c) WITH [PC:=L7], L7: L7(c) WITH [PC:=L2], L8: L8(c) WITH [PC:=LEND], LEND: c ENDCASES bool find_linear (unsigned size, const int a[], int x) { L1: i=0; L2: if(!(i<size)) goto L8; L3: if(!(a[i]==x)) goto L6; L4: result=TRUE; L5: goto LEND; L6: i++; L7: goto L2; L8: result=FALSE; LEND:; return result; } How about a program with a 1000 basic blocks?= 1000 cases? • Better not • Remedy: Modularize the program and the proof • Idea: find_linear is a function in the C program, make it a function in PVS as well C  C • Functions in PVS must be total, thus, this requires proof of termination A

  31. a T such that c(T, start)`PC=LEND Modularization find_linear(start: C): C= c(epsilon! (T: nat): c(T, start)`PC=LEND, start) "epsilon! (x:t): p(x)” is translated to "epsilon(LAMBDA (x:t): p(x))” epsilon_ax: AXIOM (EXISTS x: p(x)) => p(epsilon(p)) THIS IS WHATREQUIRES TERMINATION A

  32. Modularization termination: THEOREM FORALL (initial: C): EXISTS (T: nat): c(T, initial)`PC=LEND allows to show the left hand side of epsilon_ax: AXIOM (EXISTS x: p(x)) => p(epsilon(p)) the right hand side then says c(epsilon! (T: nat): c(T, start)`PC=LEND, start)`PC=LEND A

  33. Modularization find_linear(start: C): C= c(epsilon! (T: nat): c(T, start)`PC=LEND, start) What to prove about it? ? find_linear_correct: THEOREM FORALL (c: C): LET new=find_linear(c) IN new=c WITH [result:=correct_result(c)] What is missing? A

  34. Modularization find_linear(start: C): C= c(epsilon! (T: nat): c(T, start)`PC=LEND, start) What to prove about it? find_linear_correct: THEOREM FORALL (c: C): LET new=find_linear(c) IN new=c WITH [result:=correct_result(c), PC:=new`PC, i:=new`i] “All variables but result, PC, and i are unchanged, and result is the correct result.” A

  35. NOW LET’S PROVE THE THEOREM

More Related