diff src/tests/gov/nasa/jpf/test/mc/basic/SharedPropagationTest.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/gov/nasa/jpf/test/mc/basic/SharedPropagationTest.java	Fri Jan 23 10:14:01 2015 -0800
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014, United States Government, as represented by the
+ * Administrator of the National Aeronautics and Space Administration.
+ * All rights reserved.
+ *
+ * The Java Pathfinder core (jpf-core) platform is licensed under the
+ * Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ * 
+ *        http://www.apache.org/licenses/LICENSE-2.0. 
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package gov.nasa.jpf.test.mc.basic;
+
+import gov.nasa.jpf.util.test.TestJPF;
+import org.junit.Test;
+
+/**
+ * various shared object propagations that could lead to missed paths
+ */
+public class SharedPropagationTest extends TestJPF {
+
+  static class Gotcha extends RuntimeException {
+    // nothing in here
+  }
+  
+  //--- simple local ref 
+  
+  static class T1 extends Thread {
+
+    static class X {
+
+      boolean pass;
+    }
+    X myX; // initially not set
+
+    public static void main(String[] args) {
+      T1 t = new T1();
+      t.start();
+
+      X x = new X();
+      t.myX = x;        // (0) x not shared until this GOT executed
+
+      //Thread.yield();  // this would expose the error
+      x.pass = true;     // (1) need to break BEFORE assignment or no error
+    }
+
+    @Override
+	public void run() {
+      if (myX != null) {
+        if (!myX.pass) {  // (2) won't fail unless main is between (0) and (1)
+          throw new Gotcha();
+        }
+      }
+    }
+  }
+  
+  @Test
+  public void testLocalRef(){
+    if (verifyUnhandledException( Gotcha.class.getName(), "+vm.scheduler.sharedness.class=.vm.GlobalSharednessPolicy")){
+      T1.main(new String[0]);
+    }
+  }
+  
+  
+  //--- one reference level down
+  
+  static class T2 extends Thread {
+
+    static class X {
+      boolean pass;
+    }
+
+    static class Y {
+      X x;
+    }
+    
+    Y y;
+
+    public static void main(String[] args) {
+      T2 t = new T2();
+      Y y = new Y();
+      X x = new X();
+
+      y.x = x;
+      // neither x nor y  shared at this point
+
+      t.start();
+      t.y = y; // y becomes shared, and with it x
+
+      x.pass = true;
+    }
+
+    @Override
+	public void run() {
+      if (y != null) {
+        if (!y.x.pass) {
+          throw new Gotcha();
+        }
+      }
+    }
+  }
+  
+  @Test
+  public void testLevel1Ref(){
+    if (verifyUnhandledException(Gotcha.class.getName())){
+      T2.main(new String[0]);
+    }
+  }
+
+  //--- propagation via static field
+  
+  static class T3 extends Thread {
+
+    static class X {
+      boolean pass;
+    }
+
+    static class Y {
+      X x;
+    }
+    static Y globalY; // initially not set
+
+    
+    public static void main(String[] args) {
+      T3 t = new T3();
+      t.start();
+
+      X x = new X();
+      Y y = new Y();
+      y.x = x;
+
+      globalY = y;           // (0) x not shared until this GOT executed
+
+      //Thread.yield();  // this would expose the error
+      x.pass = true;     // (1) need to break BEFORE assignment or no error
+    }
+
+    @Override
+	public void run() {
+      if (globalY != null) {
+        if (!globalY.x.pass) {  // (2) won't fail unless main is between (0) and (1)
+          throw new Gotcha();
+        }
+      }
+    }
+  }
+  
+  @Test
+  public void testStaticFieldPropagation(){
+    if (verifyUnhandledException(Gotcha.class.getName(), "+vm.scheduler.sharedness.class=.vm.GlobalSharednessPolicy")){
+      T3.main(new String[0]);
+    }
+  }
+  
+  
+  //--- the infamous Hyber example
+  
+  static class Hyber {
+    private static Timeout thread = new Timeout();
+
+    public static void main(String[] args) {
+      thread.start();
+      Timeout.Entry timer = thread.setTimeout(); // (0)
+      //Thread.yield();    // this forces the error
+      timer.hyber = true;  // (1) we need to break here to catch the error
+    }
+  }
+
+  static class Timeout extends Thread {
+
+    static class Entry {
+      boolean hyber = false;
+      Entry next = null;
+      Entry prev = null;
+    }
+    Entry e = new Entry();
+
+    Timeout() {
+      e.next = e.prev = e;
+    }
+
+    public Entry setTimeout() {
+      Entry entry = new Entry();
+      synchronized (e) {
+        entry.next = e;
+        entry.prev = e.prev;
+        entry.prev.next = entry;
+        entry.next.prev = entry;
+      }
+
+      return entry;
+    }
+
+    @Override
+	public void run() {
+      synchronized (e) {
+        for (Entry entry = e.next; entry != e; entry = entry.next) {
+          if (!entry.hyber) { // (2) only fails if main thread between (0) and (1)
+            throw new Gotcha();
+          }
+        }
+      }
+    }
+  }
+  
+  @Test
+  public void testHyber() {
+    if (verifyUnhandledException(Gotcha.class.getName(), "+vm.scheduler.sharedness.class=.vm.GlobalSharednessPolicy")){
+      Hyber.main(new String[0]);
+    }    
+  }
+
+}