750 likes | 869 Views
JML: Expressive, Modular Reasoning for Java. Gary T. Leavens Iowa State University Support from US National Science Foundation Stanford University, March 5, 2007. jmlspecs.org. www.cs.iastate.edu/~leavens. Java Modeling Language—JML. Formal specification language for Java
E N D
JML: Expressive, Modular Reasoning for Java Gary T. LeavensIowa State University Support from US National Science FoundationStanford University, March 5, 2007 jmlspecs.org www.cs.iastate.edu/~leavens
Java Modeling Language—JML • Formal specification language for Java • Functional behavior • Sequential • Goals: • Practical, effective for detailed designs • Existing code • Wide range of tools • Hoare-style • Method pre- and postconditions • Type invariants
fieldspecification method behavior specification Example JML Specification public classAnimal implements Gendered {protected /*@ spec_public @*/int age = 0; /*@ requires0 < yrs;@ensuresage == \old(age + yrs); @*/public void older(final int yrs){ age = age + yrs; } /* … */ }
BehavioralInterface Specification JML Specification Syntactic Interface Functional Behavior Java Code
Behavioral Interface Specification /*@ requires0 < yrs;@ensuresage == \old(age + yrs); @*/public void older(final int yrs); requiresyrs > 0;ensures age == \old(age) + yrs; public void older(final int yrs); public void older(final int yrs){ age = age + yrs; }
Like … But for Java and… • VDM, but • OO features • Eiffel, but • Features for formal verification • Spec#, but • Different invariant methodology • More features for formal verification
Research Community • 23 groups, worldwide • Open • Join us • Over 125 papers See jmlspecs.org for details
Many tools, One Language Warnings JML Annotated Java ESC/Java2 public class Animal implements Gendered { // ... protected /*@ spec_public @*/ int age = 0; /*@ requires 0 <= a && a <= 150; @ ensures age == a; @ also@ requires a < 0; @ ensures age == \old(age); @*/public void setAge(final int a) {if (0 <= a) { age = a; } } } jmldoc Web pages Daikon jmlunit Data trace file Unit tests jmlc JACK, Jive, Krakatoa,KeY,LOOP Bogor Class file Correctness proof Model checking XVP
Problems for this Talk Modular Specification, Verification • Recording detailed designs • Specifying subtypes • Verification with OO features
Problem 1:Recording Detailed Designs • Precise, sequential behavior • Hide details Approach • Model fields • Assertions
Model Fields, Ensures public interface Gendered { //@ model instance String gender;//@ensures\result==gender.equals(“female”);/*@ pure@*/boolean isFemale(); }
Represents Clauses public classAnimal implements Gendered { protected boolean gen; //@ in gender; /*@ protected represents gender @ <- (gen ? “female” : “male”);@*/ // ...
Use of Model Fields public classAnimal implements Gendered { protected boolean gen; //@ in gender; /*@ protected represents gender @ <- (gen ? “female” : “male”);@*/ public/*@ pure @*/ boolean isFemale(){ return gen; } // ...
Correctness with Model Fields isFemale’sspecification “female” gender: true represents == isFemale’scode gen: true true
Requires Clauses public classAnimal implements Gendered { protected boolean gen; //@ in gender; /*@ protected represents gender @ <- (gen ? “female” : “male”);@*/ //@ requires g.equals(“female”)||g.equals(“male”);//@ ensuresgender.equals(g);public Animal(final String g){ gen = g.equals(“female”); }
Model of Method Specifications public interfaceT {//@requirespre;//@ensurespost;voidm();} T⊳(pre, post)
post m() pre Model of Method Specifications output post-state input pre-state
spec_publicShorthand Instead of: //@ public model int age;protectedint_age = 0;//@ in age;//@ protected represents age <-_age; Write: protected /*@ spec_public @*/int age = 0;
Specification Cases, ‘also’ public classAnimal implements Gendered {protected/*@ spec_public @*/int age = 0; /*@ requires0 <= a && a <= 150;@ensuresage == a; @ also@requiresa < 0;@ensuresage == \old(age); @*/public void setAge(final int a){ if (0 <= a) { age = a; } }
Join of Specification Cases requires0 <= a && a <= 150;ensuresage == a;alsorequiresa < 0;ensuresage == \old(age); means requires(0 <= a && a <= 150) || a < 0 ;ensures(\old(0 <= a && a <= 150) ==> age == a)&&(\old(a < 0) ==> age == \old(age)) ;
Join of Specification Cases post &&post′ post pre′ pre pre &&pre′
Join of Specification Cases, ⊔S If T′ ⊳ (pre′, post′), T⊳ (pre, post), S ≤ T′, S ≤ T, then (pre′, post′)⊔S (pre, post) =(p, q) wherep=pre′||preandq=(\old(pre′)==>post′) && (\old(pre)==>post )andS⊳ (p, q)
Type Specifications:Invariants import java.util.*; public classPatient extends Animal { //@ public invariant 0 <= age && age <= 150; protected/*@ spec_public @*/ List log; /*@ public invariant (\forall int i; @ 0 <= i && i < log.size();@ log.get(i) instanceof String);@*/ // …
Invariants • Hold in visible states • Method pre- & post-, Constructor post-states • Obeyed by subtypes
Invariants: Obeyed by Subtypes Not a Sugar [LW94] Animal Patient Tortoise invariant 0 <= age && age <= 150; FemalePatient
Initially public classPatient extends Animal { // ... protected/*@ spec_public @*/List log; //@ public initially log.size() == 0; • True in constructor post-states • Basis for datatype induction • Not a sugar
History Constraints [LW94] public classPatient extends Animal { // ... /*@ public constraint@\old(log.size()) <= log.size(); @ public constraint@ (\forall int i; @ 0 <= i && i < \old(log.size());@ log.get(i).equals(\old(log.get(i)))); @*/
History Constraints • Relate pre-states and post-states • Inductive step for datatype induction • Not a sugar
Problem 2: Specifying Subtypes • Avoid repetition • (Force behavioral subtyping) Approach • Specification Inheritance • Fields, type specifications • Method specification cases
added_spec T m T’s Added Specifications Declared in T (without inheritance): added_invT invariant added_hcT history constraint added_initT initially predicate m’s specification Other Notations supers(T ) = {U | T U } methods(T) = { m | m declared in TT}
added_spec U m ext_spec T m Specification Inheritance’s Meaning:Extended Specification of T • Methods: for all mmethods(supers(T)) = ⊔T { | Usupers(T) } • Invariant: ext_invT = ⋀ { added_invU | Usupers(T) } • History constraint: ext_hcT = ⋀ { added_hcU | Usupers(T) } • Initially: ext_initT = ⋀ { added_initU | Usupers(T) }
Invariant Inheritance public classFemalePatient extends Patient { //@ public invariantgender.equals(“female”);// … } • Extended invariant: added_invGendered && added_invAnimal && added_invPatient && added_invFemalePatient
Invariant Inheritance public classFemalePatient extends Patient { //@ public invariantgender.equals(“female”);// … } • Extended invariant: true && true && 0 <= age && age <= 150 && (\forall int i; 0 <= i && i < log.size(); log.get(i) instanceof String) && gender.equals(“female”)
Invariant Inheritance public classFemalePatient extends Patient { //@ public invariantgender.equals(“female”);// … } • Extended invariant: 0 <= age && age <= 150 && (\forall int i; 0 <= i && i < log.size(); log.get(i) instanceof String) && gender.equals(“female”)
Method Specification Inheritance:Supertype’s added_spec public classAnimal implements Gendered { // … /*@ requires0 <= a && a <= 150;@ensuresage == a; @ also@requiresa < 0;@ensuresage == \old(age); @*/public void setAge(final int a) { /* … */ }
Method Specification Inheritance:Subtype’s added_spec public classPatient extends Animal { // … protected/*@ spec_public @*/boolean ageDiscount = false; //@ in age;/*@ also@requires 0 <= a && a <= 150 || a < 0; @ ensures65 <= age ==> ageDiscount;@*/public void setAge(final int a) {super.setAge(a);if (65 <= age) { ageDiscount = true; }}
added_spec added_spec ext_spec Patient Animal Patient setAge setAge setAge Method Specification Inheritance:Extended Specification = ⊔Patient{ , }
Method Specification Inheritance:Extended Specification requires0 <= a && a <= 150;ensuresage == a;alsorequiresa < 0;ensuresage == \old(age);also requires 0 <= a && a <= 150 || a < 0;ensures65 <= age ==> ageDiscount;
Problem 3: Verification with OO features • Subtyping • Dynamic Dispatch Approach [LN06] • Supertype abstraction • Validity: • Assumptions about Invariants, etc., • Behavioral subtyping • Behavioral subtypingfrom specification inheritance
Supertype Abstraction Reasoning about dynamic dispatch: Gendered e = (Gendered)elems.next();if (e.isFemale()) {//@ asserte.gender.equals(“female”); // ...} Supertype abstraction: • Static type of e is Gendered • Use specification from Gendered
Static Type’s Specification public interface Gendered { //@ model instance String gender;//@ensures\result==gender.equals(“female”);/*@ pure@*/boolean isFemale(); }
Supertype Abstraction in General Use static type’s specifications to reason about: • Method calls, • Invariants, • History constraints, • Initially predicates
o.ext_pre T m o.ext_post T m Supertype Abstraction in General To = /* create a new object */; //@ assumeo.ext_initT && o.ext_invT; /* … */ //@ assert;o.m();//@ assume ;//@ assumeo.ext_invT && o.ext_hcT;
Reasoning withoutSupertype Abstraction? Case analysis: • Case for each potential dynamic type • Can exploit dynamic type’s specifications
Case Analysis+ Supertype Abstraction • Use instanceof for case analysis • Downcast, use supertype abstraction /*@ requiresp instanceof Doctor@ || p instanceof Nurse; @*/publicboolean isHead(final Staff p) {if(p instanceof Doctor) { Doctor doc = (Doctor) p;returndoc.getTitle().startsWith(“Head”); } else { Nurse nrs = (Nurse) p;returnnrs.isChief(); }}
Supertype Abstraction’s Soundness Valid if: • Invariants etc. hold as needed, and • Each subtype is a behavioral subtype
Assumption about Invariants assert Pre; assume Pre && Inv; assert Post && Inv; assume Post;
Invariant Methodology Potential problems: • Representation exposure • Reentrance Relevant invariant semantics [Mül02,MPHL06]: • Ownership type system • Re-establish invariant when call Guarantees: • invariant holds at start of method
Initially Predicates,History Constraints • Similar problems? • Similar solutions?
Behavioral Subtypes • Subtypes obey supertype specification • Subtypes: • Refine method specifications • Strengthen invariants, etc.