Space Reductions for Quasi-cyclic Systems

Document Sample
Space Reductions for Quasi-cyclic Systems Powered By Docstoc
					   Model-Checking JML
   Specifications with Bogor
              SAnToS Laboratory, Kansas State University, USA

                                                         CASSIS 2004, Marseille, France

 Robby                                       http://bogor.projects.cis.ksu.edu
 Edwin Rodríguez                             http://spex.projects.cis.ksu.edu
 Matthew B. Dwyer                            http://jmleclipse.projects.cis.ksu.e
 John Hatcliff                               http://bandera.projects.cis.ksu.edu
Support
 US Army Research Office (ARO)                    Boeing                        Lockheed Martin
 US National Science Foundation (NSF)             Honeywell Technology Center   NASA Langley
 US Department of Defense                         IBM                           Rockwell-Collins ATC
 Advanced Research Projects Agency (DARPA)        Intel                         Sun Microsystems
Bandera:
An Open Toolset for Model Checking Concurrent Java Programs
                                                          Eclipse Platform
                     Optimization Control
                                                                             Checker
                                                                             Input
             ?                    Slicing

     Specification                     Abstract
                                       Interpretation

     void add(Object o) {
                                   Static                                    Bogor
      buffer[head] = o;            Analysis
      head = (head+1)%size;
     }

     Object take() {              Transformation &
      …
      tail=(tail+1)%size;
      return buffer[tail];
                                  Abstraction Tools
     }                                                                       Checker
    Java Source                                                              Output
                                 Error Trace Mapping

                                                        Bandera
SpEx Project — Goals
   specification languages should
       have a rich set of primitives for observing program
        state
            heap-allocated objects, concurrency, etc.
       make it easy to write useful specifications
            support lightweight and deep-semantic specifications
       be checkable using a variety of analysis techniques
            model checking, testing, etc.
   We are investigating several languages
       JML (current focus), OCL, AAL, etc.
JML Reasoning Tools and Technologies
     Tool        Automaton         JML Coverage     Behavior        Scalability
 (technology)     Usability                         Coverage

    LOOP          fair (straight     very high    complete (for         poor
                line code), poor                   sequential)
                   (otherwise)

  ESC/Java           good              low          high (for         excellent
                 (annotations                      sequential),       (modular
                usually needed)                     moderate        treatment of
                                                   (otherwise)        methods)
 ESC/Java2           good            moderate       high (for         excellent
                 (annotations                      sequential),       (modular
                usually needed)                     moderate        treatment of
                                                   (otherwise)        methods)
    JMLC           excellent         moderate           low          excellent
                                                  (determined by
                                                   test harness)

   Bogor           excellent         very high       moderate      good (for unit-
                                                  (determined by        level
                                                   test harness)     reasoning)


                                        other tools such as JACK,…
JML Reasoning Tools and Technologies

Theorem Proving               Model Checking/Testing

                                 Environment
  … m(…) {                       … m(…) {
      assume pre-conditions
      …
      …
                                  checking that specifications
      …
                                  are satisfied for particular
      … manipulate formulas
                                  traces generated by the
      …
                                  environment (test harness)
      …
      prove post-conditions
  }                              }
Bogor
        Questions…
            What is it?
            Why is it useful?
            What about its
             existing algorithms
             suggests that it
             might be good for
             checking JML?
Bogor (Buitenzorg)
Bogor – Software Model Checking Framework
Bogor – Direct support for OO software
                                      Extensive support for
                                      checking concurrent OO
                                      software


Direct support for…                   Software targeted algorithms…
    unbounded dynamic creation           thread & heap symmetry
     of threads and objects
                                          compact state representation
    automatic memory
     management (garbage                  partial order reduction
     collection)                           techniques driven by
    virtual methods, …                       object escape analysis
    …, exceptions, etc.                      locking disciplines
    supports virtually all of Java
 Bogor – Eclipse-based Tool Components

Next generation of
Bandera Java Model-                               Cadena
checking Tool Set                                 CORBA Component Model
                                                  verification




SpEx
JML Verification, etc.                   Tool Development
                                               Framework


  Architecture allows encapsulation/integration with other verification
  tools using IBM’s Eclipse Integrated Development Environment
Domain-Specific Model-Checking —
Bogor Customized To Cadena
Bogor -- Extensible Modeling Language
                                  Sets
     Threads,                                               RT CORBA
     Objects,
     Methods,
     Exceptions, etc.
                           +       Queues
                                  Tables
                                                +          Event Service
                                                          API Abstraction

  Core Modeling Language          Extensions        Domain-specific Abstractions


Bogor -- Customizable Checking Engine Modules
                   Scheduling              …existing         Real-time
                    Strategy               modules…          Scheduling

  State-space     State-space              Quasi-cyclic      Partial State
  Exploration    Representation              Search         Representation

    Core Checker Modules                   Customized Checker Modules
Bogor Customized To Bandera
Bogor – Feature-rich Modeling Language

     Threads,
     Objects,
     Methods,
     Exceptions, etc.

  Core Modeling Language


Bogor -- Customizable Checking Engine Modules
                   Scheduling     …existing     Partial Order
                    Strategy      modules…       Reduction
  State-space        State        Depth-first   Symm. Reduc.
  Exploration    Representation    Search       &Compression

    Core Checker Modules          Customized Checker Modules
  Bogor’s Heap Representation
                          Heap             Key Points…
State
                                            …explicit heap representation
                                            …after each transition, a
                                            topological sort gives heap
                                            objects a canonical order
            …transition may create new
            objects, garbage, etc.          …garbage is eliminated

                                            …precise heap model
                                            …precise alias information
                                            …have access to all visited
                                            states (but, efficiently stored
                                            using collapse compression)
…sort walks over
heap, canonicalizes,             Canonical heap
and collects info
  Bogor’s Heap Representation —
  Enables JML Specs Check
                          Heap             Key Points…
State
                                            … many JML features are
                                            easy to support in Bogor

                                            …precise heap model
                                            (c.f., \reach)
            …transition may create new
            objects, garbage, etc.
                                            …precise alias information
                                            (c.f., \modifies)

                                            …can easily compare objects
                                            in methods pre/post-states
                                            (c.f., \old)

…sort walks over
heap, canonicalizes,             Canonical heap
and collects info
JML Language Coverage




              large language coverage…
Doug Lea’s LinkedQueue Example
public class LinkedNode {                       protected synchronized Object extract() {
  public Object value;                            synchronized (head) {
  public LinkedNode next;                           Object x = null;
                                                    LinkedNode first = head.next;
    public LinkedNode(Object x) {                   if (first != null) {
      value = x;                                      x = first.value;
    }                                                 first.value = null;
}                                                     head = first;
                                                    }
public class LinkedQueue {                          return x;
  protected final Object putLock;                 }
  protected LinkedNode head;                    }
  protected LinkedNode last = head;
  protected int waitingForTake = 0;
                                                protected void insert(Object x) {
                                                  synchronized (putLock) {
    public LinkedQueue() {                          LinkedNode p = new LinkedNode(x);
      putLock = new Object();                       synchronized (last) {
      head = new LinkedNode(null);                    last.next = p;
    }                                                 last = p;
                                                    }
    public boolean isEmpty() {                      if (waitingForTake > 0) putLock.notify();
      synchronized (head) {                           return;
        return head.next == null;                 }
      }                                         }
    }
                                                public Object take() {
    public void put(Object x) {                   Object x = extract();
      if (x == null)                              if (x != null) return x;
        throw new IllegalArgumentException();     else …

                                       allows a high degree of concurrency
      insert(x);                                }
    }
Doug Lea’s LinkedQueue Example


                    head

               LQ          LN
         putLock    last




  A state with two threads and a LinkedQueue object
Doug Lea’s LinkedQueue Example


                 head

            LQ          LN
      putLock    last




      The red thread creates a new object
Doug Lea’s LinkedQueue Example


      put()

                   head

              LQ          LN
       putLock     last




   …and invokes put(), which invokes insert()
Doug Lea’s LinkedQueue Example


      put()

                   head

              LQ          LN
       putLock     last




     insert() acquires the lock on putLock
Doug Lea’s LinkedQueue Example

                         p
     put()
                                   value
                  head

             LQ              LN   LN
      putLock     last




       …and creates a new LinkedNode
Doug Lea’s LinkedQueue Example

                           p
       put()
                                     value
                    head

               LQ              LN   LN
        putLock     last




  …then it locks the LinkedNode pointed by last
Doug Lea’s LinkedQueue Example

                            p
        put()
                                             value
                     head            next

                LQ              LN          LN
         putLock     last




  …and assigns new LinkedNode to last.next
Doug Lea’s LinkedQueue Example

                           p
       put()
                                            value
                    head            next

               LQ              LN          LN
        putLock
                               last




   last is moved to point to the new LinkedNode
Doug Lea’s LinkedQueue Example

                          p
      put()
                                           value
                   head            next

              LQ              LN          LN
       putLock
                              last




    the lock on head’s LinkedNode is released
Doug Lea’s LinkedQueue Example


         put()
                                          value
                      head        next

                 LQ          LN          LN
          putLock
                             last




returning from insert(), the local p is now out of scope
Doug Lea’s LinkedQueue Example


       put()
                                        value
                    head        next

               LQ          LN          LN
        putLock
                           last




    and the lock on putLock’s object is released
Doug Lea’s LinkedQueue Example


                                        value
                    head        next

               LQ          LN          LN
         putLock
                           last




  The red thread finishes executing the put() method
Doug Lea’s LinkedQueue Example


                                        value
                    head        next

               LQ          LN          LN
         putLock
                           last




 and it removes the reference to the new object, done!
Doug Lea’s LinkedQueue Example


                                     value     value
                 head        next      next

            LQ          LN          LN        LN
      putLock
                             last




                another object is added
Doug Lea’s LinkedQueue Example


                                               value     value
                           head        next      next

       take()         LQ          LN          LN        LN
                putLock
                                       last




The blue thread invokes take(), which invokes extract()
Doug Lea’s LinkedQueue Example


                                            value     value
                        head        next      next

    take()         LQ          LN          LN        LN
             putLock
                                    last




                   the LinkedQueue is locked
Doug Lea’s LinkedQueue Example


                                            value     value
                        head        next      next

    take()         LQ          LN          LN        LN
             putLock
                                    last




         the head’s LinkedNode is also locked
Doug Lea’s LinkedQueue Example


                                             value     value
                        head         next      next

    take()         LQ           LN          LN        LN
             putLock
                                     last




                        first


         head.next is assigned to the local first
Doug Lea’s LinkedQueue Example

                         x


                                             value     value
                        head         next      next

    take()         LQ           LN          LN        LN
             putLock
                                     last




                        first


             first.value is assigned to the local x
Doug Lea’s LinkedQueue Example

                         x


                                                         value
                        head         next        next

    take()         LQ           LN          LN          LN
             putLock
                                     last




                        first


                 first.value is assigned null
Doug Lea’s LinkedQueue Example

                              x

                       head
                                                           value
                                       next        next

    take()         LQ             LN          LN          LN
             putLock
                                       last




                         first


         head is moved to the next LinkedNode
Doug Lea’s LinkedQueue Example

                              x

                       head
                                                      value
                                              next

    take()         LQ                    LN          LN
             putLock
                                  last




   the LinkedNode is GC’ed (after its lock released)
Doug Lea’s LinkedQueue Example


                                      value
                  head        next

             LQ          LN          LN
       putLock
                         last



   x




           the state after take() is finished
Assessments — LinkedQueue
   put() and take()
       can be done concurrently
            if the size of the LinkedQueue is greater than 0
            they use different locks to protect object accesses
                 put() synchronizes on putLock and last
                 take() synchronizes on the LinkedQueue object and
                  head
       are mutually exclusive
            if the size is 0
            synchronize on the same LinkedNode
                 head == last
       reasoning about them becomes very complex
JML & Concurrency Issues
   Pre-/post-conditions
       check points in a concurrent setting
   Functional and synchronization aspects
       difficulty when specifying methods
   Model checking post-conditions with
    \old()
    LinkedQueue Example (JML)
public class LinkedNode {                                       /*@ behavior
                                                                  @   requires x != null;
  public Object value;
                                                                  @   ensures true;
  public LinkedNode next;                                         @ also behavior
                                                                  @   requires x == null;
    /*@ behavior                                                  @   signals (Exception e) e instanceof IllegalArgumentException;
      @   ensures value == x;                                     @*/
      @*/                                                        public void put(Object x) {
    public LinkedNode(Object x) {                                  if (x == null)
      value = x;                                                     throw new IllegalArgumentException();
    }                                                              insert(x);
}                                                                }

public class LinkedQueue {                                       protected synchronized Object extract() {
  protected final /*@ non_null @*/ Object putLock;                 synchronized (head) {
  protected /*@ non_null @*/ LinkedNode head;                        return refactoredExtract();
  protected /*@ non_null @*/ LinkedNode last = head;               }
  protected int waitingForTake = 0;                              }

    //@ instance invariant waitingForTake >= 0;                  /*@ behavior
                                                                   @   assignable head, head.next.value;
    //@ instance invariant \reach(head).has(last);
                                                                   @   ensures \result == null || (\exists LinkedNode n;
                                                                   @                               \old(\reach(head)).has(n);
    /*@ behavior                                                   @                                n.value == \result
      @   assignable head, last, putLock, waitingForTake;          @                                && !(\reach(head).has(n)));
      @   ensures \fresh(head, putLock) && head.next == null;      @*/
      @*/                                                        protected Object refactoredExtract() {
    public LinkedQueue() {                                         Object x = null;
      putLock = new Object();                                      LinkedNode first = head.next;
      head = new LinkedNode(null);                                 if (first != null) {
    }                                                                x = first.value;
                                                                     first.value = null;
    /*@ behavior                                                     head = first;
      @   ensures \result <==> head.next == null;                  }
      @*/                                                          return x;
    public boolean isEmpty() {                                   }
      synchronized (head) {
        return head.next == null;                                /*@ behavior
      }                                                            @   requires x != null;
                                                                   @   ensures last.value == x && \fresh(last);
    }
                                                                   @*/
                                                                 protected void insert(Object x) {
    /*@ behavior                                                   synchronized (putLock) {
      @ requires n != null;                                          LinkedNode p = new LinkedNode(x);
      @ assignable last, last.next;                                  synchronized (last) refactoredInsert(p);
      @*/                                                            if (waitingForTake > 0) putLock.notify();
    protected void refactoredInsert(LinkedNode n) {                    return;
      last.next = n;                                                 }
      last = n;                                                    }
    }                                                            }
    LinkedQueue Example (JML)
public class LinkedNode {                                       /*@ behavior
                                                                  @   requires x != null;
  public Object value;
                                                                  @   ensures true;
  public LinkedNode next;                                         @ also behavior
                                                                  @   requires x == null;
    /*@ behavior                                                  @   signals (Exception e) e instanceof IllegalArgumentException;
      @   ensures value == x;                                     @*/
      @*/                                                        public void put(Object x) {
    public LinkedNode(Object x) {                                  if (x == null)
      value = x;                                                     throw new IllegalArgumentException();

}
    }
     public class LinkedQueue {                                  }
                                                                   insert(x);


          protected final /*@ non_null @*/(head) {Object extract() {
public class LinkedQueue {
  protected final /*@ non_null @*/ Object putLock;
                                                                           Object putLock;
                                                         protected synchronized
                                                           synchronized

          protected /*@ = head;
  protected /*@ non_null @*/ LinkedNode last non_null @*/ }LinkedNode head;
  protected /*@ non_null @*/ LinkedNode head;                return refactoredExtract();

  protected int waitingForTake = 0;                      }
          protected /*@ non_null @*/ /*@LinkedNode last = head;
  //@ instance invariant waitingForTake >= 0;                behavior
                                                           @   assignable head, head.next.value;
                                                                = \result
          protected int waitingForTake ensures0; == null || (\exists LinkedNode n;
  //@ instance invariant \reach(head).has(last);

  /*@ behavior
                                                           @
                                                           @                               \old(\reach(head)).has(n);
                                                                   @                                n.value == \result
      @   assignable head, last, putLock, waitingForTake;          @                                && !(\reach(head).has(n)));
      @   ensures \fresh(head, putLock) && head.next == null;      @*/
      @*/
           //@ instance invariant waitingForTake >= 0;
    public LinkedQueue() {
      putLock = new Object();
                                                                 protected Object refactoredExtract() {
                                                                   Object x = null;
                                                                   LinkedNode first = head.next;

    }      //@ instance invariant \reach(head).has(last);
      head = new LinkedNode(null);                                 if (first != null) {
                                                                     x = first.value;
                                                                     first.value = null;
    /*@ behavior                                                     head = first;
      @   ensures \result <==> head.next == null;                  }
                                                                   return x;
      @*/
         …
    public boolean isEmpty() {
      synchronized (head) {
                                                                 }

        return head.next == null;                                /*@ behavior
      }                                                            @   requires x != null;
                                                                   @   ensures last.value == x && \fresh(last);
    }
                                                                   @*/
                                                                 protected void insert(Object x) {
    /*@ behavior                                                   synchronized (putLock) {
      @ requires n != null;                                          LinkedNode p = new LinkedNode(x);
      @ assignable last, last.next;                                  synchronized (last) refactoredInsert(p);
      @*/                                                            if (waitingForTake > 0) putLock.notify();
    protected void refactoredInsert(LinkedNode n) {                    return;
      last.next = n;                                                 }
      last = n;                                                    }
    }                                                            }
    LinkedQueue Example (JML)
public class LinkedNode {                                           /*@ behavior
                                                                      @   requires x != null;
  public Object value;
                                                                      @   ensures true;
  public LinkedNode next;                                             @ also behavior
                                                                      @   requires x == null;
    /*@ behavior                                                      @   signals (Exception e) e instanceof IllegalArgumentException;
      @   ensures value == x;                                         @*/
      @*/                                                            public void put(Object x) {
    public LinkedNode(Object x) {                                      if (x == null)
      value = x;                                                         throw new IllegalArgumentException();
    }                                                                  insert(x);
}                                                                    }

       /*@ behavior
public class LinkedQueue {
  protected final /*@ non_null @*/ Object putLock;
                                                              protected synchronized Object extract() {
                                                                synchronized (head) {

           @         assignable head, last, putLock, waitingForTake;
  protected /*@ non_null @*/ LinkedNode head;
  protected /*@ non_null @*/ LinkedNode last = head;            }
                                                                  return refactoredExtract();

                                                              }
           @         ensures \fresh(head, putLock) && head.next == null;
  protected int waitingForTake = 0;
                                                              /*@ behavior
    //@ instance invariant waitingForTake >= 0;
           @*/
    //@ instance invariant \reach(head).has(last);
                                                                @
                                                                @
                                                                    assignable head, head.next.value;
                                                                    ensures \result == null || (\exists LinkedNode n;
                                                                @                               \old(\reach(head)).has(n);
                      LinkedQueue() {
       public head, last, putLock, waitingForTake;
    /*@ behavior
      @   assignable
                                                                @
                                                                @
                                                                                                 n.value == \result
                                                                                                 && !(\reach(head).has(n)));
      @
      @*/  putLock = new Object();
          ensures \fresh(head, putLock) && head.next == null;   @*/
                                                              protected Object refactoredExtract() {
    public LinkedQueue() {
           head = new LinkedNode(null); Object x = first = head.next;
      putLock = new Object();                                   LinkedNode
                                                                           null;

      head = new LinkedNode(null);                              if (first != null) {
    } }                                                           x = first.value;
                                                                  first.value = null;
    /*@ behavior                                                           head = first;
      @   ensures \result <==> head.next == null;                        }
      @*/                                                                return x;
    public boolean isEmpty() {                                       }
      synchronized (head) {
        return head.next == null;                                    /*@ behavior
      }                                                                @   requires x != null;
                                                                       @   ensures last.value == x && \fresh(last);
    }
                                                                       @*/
                                                                     protected void insert(Object x) {
    /*@ behavior                                                       synchronized (putLock) {
      @ requires n != null;                                              LinkedNode p = new LinkedNode(x);
      @ assignable last, last.next;                                      synchronized (last) refactoredInsert(p);
      @*/                                                                if (waitingForTake > 0) putLock.notify();
    protected void refactoredInsert(LinkedNode n) {                        return;
      last.next = n;                                                     }
      last = n;                                                        }
    }                                                                }
    LinkedQueue Example (JML)
public class LinkedNode {                                           /*@ behavior
                                                                      @   requires x != null;
  public Object value;
                                                                      @   ensures true;
  public LinkedNode next;                                             @ also behavior
                                                                      @   requires x == null;
    /*@ behavior                                                      @   signals (Exception e) e instanceof IllegalArgumentException;
      @   ensures value == x;                                         @*/
      @*/                                                            public void put(Object x) {
    public LinkedNode(Object x) {                                      if (x == null)
      value = x;                                                         throw new IllegalArgumentException();
    }                                                                  insert(x);
}                                                                    }

            /*@ behavior
public class LinkedQueue {
  protected final /*@ non_null @*/ Object putLock;
                                                              protected synchronized Object extract() {
                                                                synchronized (head) {
                                                                  return refactoredExtract();
                 @         ensures \result <==>} }head.next == null;
  protected /*@ non_null @*/ LinkedNode head;
  protected /*@ non_null @*/ LinkedNode last = head;
  protected int waitingForTake = 0;

    //@ instance @*/ waitingForTake >= 0;
                 invariant                                    /*@ behavior
                                                                @   assignable head, head.next.value;
            public boolean isEmpty() { @ ensures \result == null || (\exists LinkedNode n;
    //@ instance invariant \reach(head).has(last);

    /*@ behavior
                                                                @                               \old(\reach(head)).has(n);
                                                                @                                n.value == \result
      @
      @          synchronized (head) {
          assignable head, last, putLock, waitingForTake;
          ensures \fresh(head, putLock) && head.next == null;
                                                                @
                                                                @*/
                                                                                                 && !(\reach(head).has(n)));
      @*/
                      return head.next == null; xObject refactoredExtract() {
    public LinkedQueue() {
      putLock = new Object();
                                                              protected
                                                                Object   = null;
                                                                LinkedNode first = head.next;

    }            }
      head = new LinkedNode(null);                              if (first != null) {
                                                                  x = first.value;
                                                                  first.value = null;

      @
            } \result <==> head.next == null;
    /*@ behavior
          ensures                                               }
                                                                  head = first;

      @*/                                                                return x;
    public boolean isEmpty() {                                       }
      synchronized (head) {
        return head.next == null;                                    /*@ behavior
      }                                                                @   requires x != null;
                                                                       @   ensures last.value == x && \fresh(last);
    }
                                                                       @*/
                                                                     protected void insert(Object x) {
    /*@ behavior                                                       synchronized (putLock) {
      @ requires n != null;                                              LinkedNode p = new LinkedNode(x);
      @ assignable last, last.next;                                      synchronized (last) refactoredInsert(p);
      @*/                                                                if (waitingForTake > 0) putLock.notify();
    protected void refactoredInsert(LinkedNode n) {                        return;
      last.next = n;                                                     }
      last = n;                                                        }
    }                                                                }
Pre/Post-Conditions
                                       jmlc generates a
                                       wrapper method for each
                                       annotated method




   Figure 4.3, “A Runtime Assertion Checker for the Java Modeling Language”, Y. Cheon
Pre/Post-Conditions

                                        check invariants and
                                        method preconditions




   Figure 4.3, “A Runtime Assertion Checker for the Java Modeling Language”, Y. Cheon
Pre/Post-Conditions


                                            call original method




   Figure 4.3, “A Runtime Assertion Checker for the Java Modeling Language”, Y. Cheon
Pre/Post-Conditions


                                                   check post-conditions




   Figure 4.3, “A Runtime Assertion Checker for the Java Modeling Language”, Y. Cheon
Pre/Post-Conditions
/*@ behavior
  @   ensures \result <==> head.next == null;
  @*/
public boolean isEmpty() {
  synchronized (head) {
    return head.next == null;
  }
}
                                       At this point a thread can
                                       interleave and insert an
public boolean isEmpty() {             object in the LinkedQueue;
    …                                  so there actually exists an
    boolean rac$result;                execution race where the
    …
                                       post-condition is violated.
        rac$result = orig$isEmpty();
        checkPost$isEmpty$LinkedQueue(rac$result);
        return rac$result;
    …
}
Pre/Post-Conditions
/*@ behavior
  @   ensures \result <==> head.next == null;
  @*/
public boolean isEmpty() {
  synchronized (head) {
    return head.next == null;
  }
}




public boolean isEmpty() {
    …                                  In general, a thread can
    boolean rac$result;                interfere before or during
    …                                  the post-conditions check.
        rac$result = orig$isEmpty();
        checkPost$isEmpty$LinkedQueue(rac$result);
        return rac$result;
    …
}
Pre/Post-Conditions
/*@ behavior
  @   ensures \result <==> head.next == null;
  @*/
public boolean isEmpty() {
  synchronized (head) {
    return head.next == null;
  }
}



                                       Thus, we need to prevent the
public boolean isEmpty() {
                                       interleaving by aggregating the
    …
    boolean rac$result;
                                       return transition with the post-
    …
                                       condition transitions.
        rac$result = orig$isEmpty();
        checkPost$isEmpty$LinkedQueue(rac$result);
        return rac$result;
    …
}
Assessments — Pre/Post-conditions
    granularity of execution/checking steps
     must be controlled
        easy to do in a model checker
             using similar construct such as Promela’s atomic
        needs to modify JVM for testing
             the scheduler must prevent context-switching
              when evaluating code from specifications
JML & Concurrency Issues
   Pre-/post-conditions
       check points in a concurrent setting
   Functional and synchronization aspects
       difficulty when specifying methods
   Model checking post-conditions with
    \old()
    Functional and
    Synchronization Aspects
public class LinkedNode {                                             /*@ behavior
                                                                        @   requires x != null;
                 public Object take() {
  public Object value;
  public LinkedNode next;
                                                                        @   ensures true;
                                                                        @ also behavior
                    Object x = extract();                               @   requires x == null;
    /*@ behavior
                    if (x
          ensures value == x; != null) return x;
                                                                        @   signals (Exception e) e instanceof IllegalArgumentException;
      @                                                                 @*/
      @*/
                    else … // wait
    public LinkedNode(Object x) {
                                                                       public void put(Object x) {
                                                                         if (x == null)
      value = x; }                                                         throw new IllegalArgumentException();
    }                                                                    insert(x);
}                                                                      }
                 /*@ behavior
public class LinkedQueue {                                         protected synchronized Object extract() {
                    @      assignable head, head.next.value; refactoredExtract();
  protected final /*@ non_null @*/ Object putLock;                   synchronized (head) {
                                                                       return
  protected /*@ non_null @*/ LinkedNode head;
                    @      ensures \result == null
  protected /*@ non_null @*/ LinkedNode last = head;                 }
                                                                   }
                    @
  protected int waitingForTake = 0;      || (\exists LinkedNode n;
                    @
    //@ instance invariant waitingForTake >= 0; \old(\reach(head)).has(n);
                                                                   /*@ behavior
                                                                     @   assignable head, head.next.value;
    //@ instance invariant \reach(head).has(last);
                    @                           n.value == \result@ ensures \result == null || (\exists LinkedNode n;
                                                                     @                               \old(\reach(head)).has(n);
    /*@ behavior
      @
                    @                                && !(\reach(head).has(n)));
          assignable head, last, putLock, waitingForTake;
                                                                     @                                n.value == \result
                                                                     @                                && !(\reach(head).has(n)));
      @             @*/
          ensures \fresh(head, putLock) && head.next == null;        @*/
      @*/
                 protected synchronized Object extract() x{= null;
    public LinkedQueue() {
                                                                   protected Object refactoredExtract() {
                                                                     Object
      putLock = new synchronized (head) {
                    Object();                                        LinkedNode first = head.next;
      head = new LinkedNode(null);                                   if (first != null) {
    }                  Object x = null;                                x = first.value;
                                                                       first.value = null;
    /*@ behavior       LinkedNode first = head.next;                   head = first;
      @                if (first
          ensures \result <==> head.next != null) {
                                         == null;                    }
      @*/                                                            return x;
                           x
    public boolean isEmpty() { = first.value;                      }
      synchronized (head) {
        return head.next ==first.value = null;
                            null;                                  /*@ behavior
                                                                     @   requires x != null;
    }
      }                    head = first;                             @   ensures last.value == x && \fresh(last);
                       }                                             @*/

                                                                     does not work, why?
                                                                   protected void insert(Object x) {
    /*@ behavior
                       return x;
      @ requires n != null;
                                                                     synchronized (putLock) {
                                                                       LinkedNode p = new LinkedNode(x);
      @ assignable }last, last.next;                                   synchronized (last) refactoredInsert(p);
      @*/                                                              if (waitingForTake > 0) putLock.notify();
                 }
    protected void refactoredInsert(LinkedNode n) {                      return;
        last.next = n;                                                         }
        last = n;                                                          }
    }                                                                  }
Functional and
Synchronization Aspects


                    head

               LQ          LN
         putLock    last




  A state with two threads and a LinkedQueue object
 Functional and
 Synchronization Aspects


                             head


         take()         LQ          LN
                  putLock    last




The blue thread invokes take(), which invokes extract().
Note that the pre-state for take() is an empty LinkedQueue.
Functional and
Synchronization Aspects


         put()

                        head


    take()         LQ          LN
             putLock    last




   The red thread interleaves and put() an object
Functional and
Synchronization Aspects


                                            value
                        head        next

    take()         LQ          LN          LN
             putLock
                               last




   The red thread interleaves and put() an object
Functional and
Synchronization Aspects


                        head


    take()         LQ          LN
             putLock    last




    x




         The blue thread successfully take() the object
Functional and
Synchronization Aspects
   public Object take() {
     Object x = extract();
     if (x != null) return x;
     else … // wait
   }

   /*@ behavior
     @    assignable head, head.next.value;
                       head
     @    ensures \result == null
     @             || (\exists LinkedNode n;
     @take()       LQ \old(\reach(head)).has(n);
                              LN
     @                 n.value == \result
     @       putLock    last !(\reach(head).has(n)));
                           &&
     @*/
   protected synchronized Object extract() {
     synchronized (head) {
      x Object x = null;
        LinkedNode first = head.next;
        if (first != null) {
          x = first.value;                    functional property
          first.value = null;

        }
           but the post-condition is violated since
          head = first;

           the pre-state is an empty LinkedQueue!
        return x;
     }
   }
    Functional and
    Synchronization Aspects
                                                                       /*@ behavior
                 protected synchronized Object @extract() {
public class LinkedNode {
  public Object value;
                                                        requires x != null;
                                                     @ ensures true;
                     synchronized (head) {
  public LinkedNode next;                            @ also behavior
                                                     @ requires x == null;
    /*@ behavior
      @
                          return refactoredExtract(); signals (Exception e) e instanceof IllegalArgumentException;
          ensures value == x;
                                                     @
                                                     @*/
      @*/            }
    public LinkedNode(Object x) {
                                                   public void put(Object x) {
                                                     if (x == null)
      value = x; }                                     throw new IllegalArgumentException();
    }                                                                      insert(x);
}                                                                      }

                  /*@ behavior
public class LinkedQueue {                                          protected synchronized Object extract() {
  protected final /*@ non_null @*/ Object putLock;                    synchronized (head) {
                     @        assignable head, head.next.value;
  protected /*@ non_null @*/ LinkedNode head;                           return refactoredExtract();
                                                                      }
                     @        ensures \result == null
  protected /*@ non_null @*/ LinkedNode last = head;
  protected int waitingForTake = 0;                                 }

                     @                        || (\exists LinkedNode n;
    //@ instance invariant waitingForTake >= 0;                     /*@ behavior
                                                                      @   assignable head, head.next.value;
                     @
    //@ instance invariant \reach(head).has(last);
                                                      \old(\reach(head)).has(n); (\exists LinkedNode n;
                                                                      @   ensures \result == null ||
                                                                      @                               \old(\reach(head)).has(n);
    /*@ behavior
      @
                     @                                  n.value == @\result
          assignable head, last, putLock, waitingForTake;
                                                                                                       n.value == \result
                                                                      @                                && !(\reach(head).has(n)));
      @
      @*/
                     @                                      && !(\reach(head).has(n)));
          ensures \fresh(head, putLock) && head.next == null;         @*/
                                                                    protected Object refactoredExtract() {
                     @*/
    public LinkedQueue() {
      putLock = new Object();
                                                                      Object x = null;
                                                                      LinkedNode first = head.next;
                  protected Object refactoredExtract() null) {
      head = new LinkedNode(null);                                    if (first !=   {
    }                                                                   x = first.value;
                     Object x = null;                                   first.value = null;
    /*@ behavior                                                        head = first;
      @              LinkedNode null;
          ensures \result <==> head.next == first = head.next;        }
      @*/                                                             return x;
                     if (first != null) {
    public boolean isEmpty() {                                      }

                          == = first.value;
         return head.next x null;
      synchronized (head) {
                                                                    /*@ behavior
                                                                      @ requires x != null;
    }
      }
                          first.value = null;                         @ ensures last.value == x && \fresh(last);
                                                                      @*/
    /*@ behavior
                          head = first;                             protected void insert(Object x) {
                                                                      synchronized (putLock) {
                     } last.next;
      @ requires n != null;
      @ assignable last,
                                                                        LinkedNode p = new LinkedNode(x);
                                                                        synchronized (last) refactoredInsert(p);
      @*/            return x;
    protected void refactoredInsert(LinkedNode n) {
                                                                        if (waitingForTake > 0) putLock.notify();
                                                                          return;
      last.next = }
                  n;                                                  }
        last = n;                                                      }
    }
Assessments — Functional and
Synchronization Aspects
    when specifying properties of concurrent
     programs
        separate functional properties from synchronization
         aspects
             e.g., region of code after lock acquires
        if not, we often end up with weaker properties
    a tool support for checking specifications is
     valuable for “debugging” specifications
        model checking is good for catching subtle issues in
         concurrent programs or their properties
JML & Concurrency Issues
   Pre-/post-conditions
       check points in a concurrent setting
   Functional and synchronization aspects
       difficulty when specifying methods
   Model checking post-conditions with
    \old()
Post-conditions with \old
  “good” pre-state                     “bad” pre-state

                 … m(…) {




  passed post-                         the state has been
  conditions                           seen before, thus,
                 }                     the model checker
                                       backtracks without
              Backtracking can cause   checking post-
              MC to miss some errors   conditions
Post-conditions with \old
class Race extends Thread {   Backtracking can cause
  static int x;
                              MC to miss some errors
  public void run() {
    loc1 : x = 0;
    loc2 : foo();
  }

 /*@ ensures
   @   \old(x) == 0;
   @*/
  void foo() {
    loc3 : x = 1;
    loc4 : return;
  }
}
Post-conditions with \old
/*@ behavior
  @   ensures … \old(e) …;
  @*/
public void foo() {
  …
}




public void foo() {
  old$rac = e;               Works for primitive types,
  …
}                            but not for objects
Post-conditions with \old
/*@ behavior
  @   ensures … \old(e) …;
  @*/
public void foo() {
  …
}




public void foo() {
  int tmp = Bogor.collapseState(e);
  …
                                      If e is a reference type,
}                                     then record all reachable
                                      objects from e
Post-conditions with \old
/*@ behavior
  @   ensures … \old(e) …;
  @*/
public void foo() {
  …
}




public void foo() {
  int tmp = Bogor.collapseState(e);
  …
                                      Returns a unique integer
}                                     representing the canonical
                                      reachable heap
Post-conditions with \old
/*@ behavior
  @   assignable head, head.next.value;
  @   ensures \result == null
  @           || (\exists LinkedNode n;
  @               \old(\reach(head)).has(n);
  @                n.value == \result
  @
                                          uses set symmetry and
                     && !(\reach(head).has(n)));
  @*/                                     collapse compression
protected Object refactoredExtract() for efficiency
                                           {
  Object x = null;
  LinkedNode first = head.next;
  if (first != null) {
    x = first.value;
    first.value = null;                               value   value
                                       head     next    next
    head = first;
  }                                 LQ       LN      LN      LN
                       take()
  return x;
}                             putLock
                                               last


                                more optimizations are possible
Assessments —
Post-conditions with \old
    Backtracking can cause a model checker to miss
     some errors when checking post-conditions with
     \old
    Needs to distinguish pre-states to avoid
     backtracking too early
        uses heap symmetry to reduce the number of
         distinguishable (observationally inequivalent) pre-
         states
        uses collapse compression to reduce memory
         consumptions for encoding the pre-states
        can be optimized further by using a static analysis to
         detect relevant heap objects (analogous to slicing)
Preliminary Results
                                   w/ JML     w/o JML




Test Platform
JDK 1.4.1 (32-bit mode) on a 2 GHz Opteron with maximum
heap of 1 GB running Linux (64-bit mode)
Bogor’s Reduction Algorithms —
Enables Checking JML Specs
              w/ POR               w/o POR
          w/ JML w/o JML      w/ JML    w/o JML




               Indicates little overhead compared with
               simply exploring the state-space
JMLEclipse
                                                                        jmlc
 /*@ behavior
     @ requires x != null;
     @ ensures true;
     @also
     @ behavior


                                                                        other
     @ requires x == null;
     @ signals (Exception e) e instanceof
     @               IllegalArgumentException;
     @*/


                                                                         tool
   public void put(Object x)
   {
      if (x == null)
          throw new IllegalArgumentException();
      insert(x);
   }




JML annotated
 Java source
                                                  JML well-formedness
                                                       checker
 JMLEclipse


                          JML well-formedness checking




JML syntax highlighting
Conclusion
   There have been many tools for checking JML specifications
   Bogor flexible model checking framework can be used to check
    “strong” specifications
       Complete control over the model checker representations and
        algorithms
            hard to do it with Spin, but it can be done in JPF
       Highly-automated for unit-sized concurrent Java programs
       requires effective reductions to help curb specification checking
        overhead
       complements other JML checking methods
            checking a different class of properties
   Issues in JML support for concurrency
       Pre-/post-conditions
            check points in a concurrent setting
       Functional and synchronization aspects
            difficulty when specifying methods
       Checking \old() using model checking
Future Work
   propose specifications for concurrency
    in JML (w/ Cormac Flanagan)
       thread-locality
       method-locality
       lock-protected
       pre-/post-conditions on code regions
       atomicity, etc.
   JMLEclipse as an open ended JML plugin
    for Eclipse
   other specification formalisms
Bogor Tutorial at ETAPS 2004
   Barcelona, Spain
   April 3, half-day, afternoon
   Topics
       Adapting Bogor to a particular domain
            Extending the Bogor modeling language
                 add new abstract data types
                 add new abstract operations
            Extending the Bogor model checking algorithms
For More Information…
            SAnToS Laboratory,
            Kansas State University
            http://www.cis.ksu.edu/santos


            Bogor Project
            http://bogor.projects.cis.ksu.edu

            SpEx Project
            http://spex.projects.cis.ksu.edu

            JMLEclipse Project
            http://jmleclipse.projects.cis.ksu.edu

            Bandera Project
            http://bandera.projects.cis.ksu.edu

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:4
posted:9/6/2011
language:Indonesian
pages:79