470 likes | 483 Views
Politecnico di Milano Advanced Topics in Software Engineering. JML in a Nutshell. Domenico Bianculli & Alessandro Monguzzi. {bianculli, alessandro.monguzzi}@gmail.com. June 16th, 2005. Rev. 1.3. Outline. What is JML? Syntax Specification cases Advanced topics Running example Tools
E N D
Politecnico di MilanoAdvanced Topics in Software Engineering JML in a Nutshell Domenico Bianculli & Alessandro Monguzzi {bianculli, alessandro.monguzzi}@gmail.com June 16th,2005 Rev. 1.3
Outline • What is JML? • Syntax • Specification cases • Advanced topics • Running example • Tools • Related works
What is JML? • Java Modeling Language • A behavior interface specification language (BISL) describes: • modules interface • modules behaviour • evolution of Hoare-style specification • based on Design by Contract
Syntax • Annotations • Expressions • Quantification
Syntax: annotations • Specification written as annotation comments • Single line://@ … specification … • Multiline:/*@ … specification… @ … @*/ • Informal://@(* informal description *)
Syntax: expressions • Expression used in JML annotations cannot have side effects. • No use of =, +=, ++, -- … • Can only call pure methods • Extended version of Java expressions
Syntax: quantification • universal & existential (\forall,\exists) /*@ \forall int x; @ x >= 0 && x < a.lenght-1; @ a[x-1] <= a[x]; @*/ • general quantifiers (\sum, \product, \min, \max) • numeric quantifier(\num_of) declaration range body
Preconditions • Say what must be true when calling a method • Introduced by requires clause /*@requires x>= 0; @... @*/ public double sqrt(double x);
Normal postconditions • Say what must be true when a method returns normally(i.e. without throwing exceptions) • Introduced by ensures clause /*@ requires x>= 0; @ ensures x - \result * \result <= 0.0001; @*/ public double sqrt(double x); • Input parameters in postconditions are always evaluated in pre-statex ≡ \old(x)
Exceptional postconditions • Say what must be true when a method throws an exception of type TIntroduced by signals clause /*@ requires x>= 0; @ ensures x - \result * \result <= 0.0001; @ signals (IllegalArgumentException ex) @ ex.getMessage() != null && !(x >=0.0); @*/ public double sqrt(double x);
More on exceptional postconditions (1) • Note that signal clause does not say which exceptions must be thrown • It just only says “… if an exception of (sub)type T is thrown, then its predicate must hold” and not viceversa. • The signals_only clause specifies what exceptions may be thrown, and implicitly the ones which cannot be thrown.
More on exceptional postconditions (2) • To say that an exception must be thrown in some situations, exclude that situations from other signals clauses and from all ensures clauses/*@ requires true; @ ensures x>=0 &&… @ signals (Exception e) @ x<0 && … @*/public int foo(int x) throws Exceptions; • More on this topic later…
Semantics • Meaning of JML method specification • A method is called in a state (pre-state) where the precondition is satisfied; otherwise, nothing is guaranteed, including the termination of the call • If a method is called in a proper pre-state, then there are two possible outcomes (post-state) of method’s execution: normal and exceptional
Kinds of specification & specification cases • Specification cases • Lightweight • Heavyweight • Behaviour • Normal Behaviour • Exceptional Behaviour
Heavyweight vs lightweight specs Heavyweight • Assumes users giving full specification • Omitted clauses are abbreviations • Useful for formal verification Lightweight • Don’t assume user is giving full specification • Minimize annotation burden • Omitted clauses are \not_specified • Useful for RAC and docs
Heavyweight specs: behavior /*@ behavior @ requires P; @ diverges D; @ assignable A; @ when W; @ ensures Q; @ signals (E1 e1) R1; @ ... @ signals (En en) Rn; @ accessible C; @ callable p(); @*/
Heavyweight specs:normal behavior • It is a behavior specification case with signals clause implicitly defined as signals (java.lang.Exception) false; • guarantees normal termination no exception may be thrown
Heavyweight specs:exceptional behavior • It is a behavior specification case with ensures clause implicitly defined as ensures false; • Guarantees that the method throws an exception
Multiple cases specs • Normal and exceptional spec cases may be combined /*@ public normal_behavior @ requires !theStack.isEmpty(); @ assignable size, theStack; @ ensures @ theStack.equals(\old(theStack.trailer())) @ && \result == \old(theStack.first()); @ also @ public exceptional_behavior @ requires theStack.isEmpty(); @ assignable \nothing; @ signals_only IllegalStateException; @*/ public Object pop();
Class invariants • Properties that must hold in all visible states of an object//@ public invariant x != null && !name.equals(“”); • Static or Instance invariants • Implicitly included in preconditions and normal and exceptional postconditions • Do not hold for methods declared with clause helper • private invariants state Rep Invariant
Loop (in)variants • Loop statements can be annotated with loop invariants and variant functions. • Help in proving partial and total correctness of the loop statementlong sum = 0;int[] a = new int[100];int i = a.length;/*@ mantaining -1 <= i && i <= a.length; @ mantaining sum == @ (\sum int j; i <= j && 0 <= j @ && j <= a.length; a[j]); @ decreasing i; @*/while (--i>=0) sum += a[i];
Assertions • An assertion is a predicate that must always be true//@ assert i>0 • w.r.t. Java 1.4+ assert JML assertions cannot have any side-effects and can use JML expressions.
History Constraints • “Relationships that should hold for the combination of each visible state and any visible state that occurs later in the program execution” • Used to constrain the way the values change over time int a; //@ constraint a == \old(a); boolean[] b; //@ constraint b.lenght >= \old(b.lenght);
Advanced Topics • Model fields • Model methods and types • Fields visibility • Abstract models • Purity • Data groups • Specification inheritance • Refinement
Model fields • Represents a field or a variable used only in specification • Describes abstract values of objects • They can be mapped on a concrete field using keyword represents public class MathFoo { //@ public model eps private float error; //@ private represents eps <- error; }
Visibility • JML imposes visibility rules similar to Java • Keyword spec_public loosens visibility for specs. Private spec_public fields are allowed in public specs. private /*@ spec_public @*/ double x = 0.0;//@requires !Double.isNaN(x+dx)public void moveX(double dx){… • Not a good practice! You are exposing internal representation!
Abstract models • JML provides a Java class library for specification purposes • Package org.jmlspecs.model • Collections: sequence, set, bag • Algebric functions and relations • Exceptions and iterators • Almost all are immutable objects with pure methods • Can be used during RAC • Users can define their own models
Purity • A pure method is a method without side effects (\assignable nothing) • It is declared with the modifier pure • A class is pure if all its methods are pure • Only pure method are allowed in specifications
Data groups • A set of model and concrete fields to which you refer by a specific name • A declaration of a model field automatically creates a data group with the same name of the model field • The main purpose of a data group is to refer to the elements of this set without exposing their internal representation • Locations members of a data group may be assigned during the executions of methods that have permission to assign to the data group /*@ public model int size; @ public model JMLObjectSequence theStack; @ in size; @*/
Specification inheritance • A subclass inherits specifications of its superclass and of its implemented interfaces • All instance model fields • Instance method specifications • Instance invariants and instance history constraints • Specifications of a superclass are conjuncted with new specs with the clause also • Support behavioural notion of subtyping, accordingly to Liskov’s substitution principle: • preconditions are disjoined • postconditions are conjoined as ∩ (old(prei) -> posti) • invariants are conjoined
Refinement files • Specifications can be separated from implementations • Specs are written in a file Foo.java-refined • Implementation is written in file Foo.java which contains the clause //@refine “Foo.java-refined” • Useful for adding specifications to existing code
Example: IntSet • Informal specification“IntSets are unbounded sets of integers with operations to create a new empty IntSet, test whether a given integer is an element of an IntSet, and add or remove elements.”
IntSet à la Liskov (1) public interface IntSet { public void insert(int x) //MODIFIES: this //EFFECTS: Adds x to the elements of this public void remove(int x) //MODIFIES: this //EFFECTS: Removes x from this public boolean isIn(int x) //EFFECTS: If x is in this returns true, else returns false. } Mutator Mutator Observer
IntSet à la Liskov (2) public class IntSetAs_list implements IntSet{ … private Vector els; public IntSetAs_list(){ //EFFECTS: Initializes this to be empty. els = new Vector(); } … } • Abstraction FunctionAF(c) = {c.els.get(i).intValue | 0 <= i < c.els.size} • Representation Invariantc.els != null &&for all integers i (0 <= i < c.els.size => c.els.get(i) is an Integer) &&for all integers i, j | (0<= i < j < c.els.size => c.els.get(i).intValue != c.els.get(j).intValue)
IntSet in JML (1) public interface IntSet { /*@ public model instance JMLValueSet theSet; @ public initially theSet != null && theSet.isEmpty(); @ public instance invariant theSet != null @ && (\forall JMLType e; theSet.has(e); @ e instanceof JMLInteger); @*/ /** Insert the given integer into this set. */ /*@ public normal_behavior @ assignable theSet; @ ensures theSet.equals(\old(theSet.insert(new JMLInteger(elem)))); @*/ public void insert(int elem); /** Tell if the argument is in this set. */ /*@ public normal_behavior @ ensures \result == theSet.has(new JMLInteger(elem)); @*/ public /*@ pure @*/ boolean isIn(int elem); /** Remove the given integer from this set. */ /*@ public normal_behavior @ assignable theSet; @ ensures theSet.equals( \old(theSet.remove(new JMLInteger(elem))) ); @*/ public void remove(int elem);} Model Field Abstract Invariant
IntSet in JML (2) import java.util.*; //@ model import org.jmlspecs.models.*; public class IntegerSetAsList implements IntSet { private Vector els; //@ in theSet; /*@ private invariant els != null && @ (\forall int i; 0<=i && i<els.size(); els.get(i) != null && @ els.get(i) instanceof Integer && @ (\forall int j=0; i<j && j<els.size(); els.get(i) != els.get(j))); @*/ //@ private represents theSet <- abstractValue(); /** Return the abstract value of this IntegerSetAsList. */ /*@ @ private pure model JMLValueSet abstractValue() { @ JMLValueSet ret = new JMLValueSet(); @ Iterator iter = els.iterator(); @ while (iter.hasNext()) { @ ret = ret.insert(new JMLInteger((Integer) @ iter.next())); @ } @ return ret; @} @*/ Rep Invariant Abstraction Function
IntSet in JML (3) /** Initialize this set to be the empty set. */ /*@ public normal_behavior @ assignable theSet; @ ensures theSet != null && theSet.isEmpty(); @*/ public IntegerSetAsList() { els = new Vector(); } public /*@ pure @*/ boolean isIn(int i) { return els.contains(new Integer(i)); } public void insert(int i) { els.add(new Integer(i)); } public void remove(int i) { els.remove(new Integer(i)); }
Tools • Parsing & Typechecking • Runtime assertion checking • Testing • Documentation • Extended static checking • Program verification
jmlc • The JML compiler • Translates Java code with JML assertions into bytecode • Adds runtime checks: • During execution, all assertions are tested and any violation of an assertion produces an Error (uses jmlrac script).
jmlunit • Inserts support for JML within JUnit • Writes out a JUnit test oracle for given Java files • Specifications are used to check whether tested code runs properly Tests are only as good as the quality of the specifications!
Produces HTML pages with API and JML specifications for Java classes jmldoc
ESC/Java • Extended Static Checker for Java • Tries to prove correctness of specifications at compile-time, fully automatically • Not sound: it may miss an error that is actually present • Not complete: it may warn of errors that are impossible • It finds a lot of potential bugs quickly: • NullPointer, ArrayIndexOutOfBounds, ClassCast…
LOOP • Logic of Object Oriented Programming, project of University of Nijmegen • Based on a formalization of Java and JML semantics in the theorem prover PVS • LOOP compiler translates JML annotations in PVS proof obligations, to be proved interactively
Related Works • Early programming languages • Gypsy • Alphard • Euclid • CLU • DBC based • Eiffel • SPARK • B method • OCL from UML • Spec#
Conclusions Strenghts • Easy to learn • Source code is the formal model • Gradual introduction • Support for legacy code • Wide range of tools Weakenesses • No support for: • concurrency • object invariants within callbacks • modeling alias relationships • Strong definition of pure methods: • many constraints
References www.jmlspec.org