// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.BitSet; import java.util.Random; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; /** * Verify is the programmatic interface of JPF that can be used from inside of * applications. In order to enable programs to run outside of the JPF * environment, we provide (mostly empty) bodies for the methods that are * otherwise intercepted by the native peer class */ public class Verify { static final int MAX_COUNTERS = 10; static int[] counter; // only here so that we don't pull in all JPF classes at RT private static Random random; /* * only set if this was used from within a JPF context. This is mainly to * enable encapsulation of JPF specific types so that they only get * pulled in on demand, and we otherwise can still use the same Verify class * for JPF-external execution. We use a class object to make sure it doesn't * get recycled once JPF is terminated. */ static Class<?> peer; private static Random getRandom() { if (random == null) { random = new Random(42); } return random; } /* * register the peer class, which is only done from within a JPF execution * context. Be aware of that this migh actually load the real Verify class. * The sequence usually is * JPF(Verify) -> VM(JPF_gov_nasa_jpf_vm_Verify) -> VM(Verify) */ public static void setPeerClass (Class<?> cls) { peer = cls; } public static int getCounter (int id) { return getCounter(id, FeatureExprFactory.True()); } // note this is NOT marked native because we might also call it from host VM code // (beware that Verify is a different class there!). When executed by JPF, // this is an MJI method public static int getCounter (int id, FeatureExpr ctx) { if (peer != null) { // this is executed if we are in a JPF context return JPF_gov_nasa_jpf_vm_Verify.getCounter__I__I(null, 0, id, ctx); } else { if (counter == null) { counter = new int[id >= MAX_COUNTERS ? (id+1) : MAX_COUNTERS]; } if ((id < 0) || (id >= counter.length)) { return 0; } return counter[id]; } } public static void resetCounter (int id) { resetCounter(id, FeatureExprFactory.True()); } public static void resetCounter (int id, FeatureExpr ctx) { if (peer != null){ JPF_gov_nasa_jpf_vm_Verify.resetCounter__I__V(null, 0, id, ctx); } else { if ((counter != null) && (id >= 0) && (id < counter.length)) { counter[id] = 0; } } } public static void setCounter (int id, int val) { setCounter(id, val, FeatureExprFactory.True()); } public static void setCounter (int id, int val, FeatureExpr ctx) { if (peer != null){ JPF_gov_nasa_jpf_vm_Verify.setCounter__II__V(null, 0, id, val, ctx); } else { if ((counter != null) && (id >= 0) && (id < counter.length)) { counter[id] = val; } } } public static int incrementCounter (int id) { return incrementCounter(id, FeatureExprFactory.True()); } public static int incrementCounter (int id, FeatureExpr ctx) { if (peer != null){ return JPF_gov_nasa_jpf_vm_Verify.incrementCounter__I__I(null, 0, id, ctx); } else { if (counter == null) { counter = new int[(id >= MAX_COUNTERS) ? id+1 : MAX_COUNTERS]; } else if (id >= counter.length) { int[] newCounter = new int[id+1]; System.arraycopy(counter, 0, newCounter, 0, counter.length); counter = newCounter; } if ((id >= 0) && (id < counter.length)) { return ++counter[id]; } return 0; } } public static final int NO_VALUE = -1; public static void putValue (String key, int value) { throw new UnsupportedOperationException("putValue requires JPF execution"); } public static int getValue (String key) { throw new UnsupportedOperationException("getValue requires JPF execution"); } // same mechanism and purpose as the counters, but with BitSets, which is // more convenient if we have a lot of different events to check static BitSet[] bitSets; private static void checkBitSetId(int id) { if (bitSets == null) { bitSets = new BitSet[id + 1]; } else if (id >= bitSets.length) { BitSet[] newBitSets = new BitSet[id + 1]; System.arraycopy(bitSets, 0, newBitSets, 0, bitSets.length); bitSets = newBitSets; } if (bitSets[id] == null) { bitSets[id] = new BitSet(); } } public static void setBitInBitSet(int id, int bit, boolean value) { setBitInBitSet(id, bit, value, FeatureExprFactory.True()); } public static void setBitInBitSet(int id, int bit, boolean value, FeatureExpr ctx) { if (peer != null){ // this is executed if we did run JPF JPF_gov_nasa_jpf_vm_Verify.setBitInBitSet__IIZ__V(null, 0, id, bit, value, ctx); } else { // this is executed if we run this without previously executing JPF checkBitSetId(id); bitSets[id].set(bit, value); } } public static boolean getBitInBitSet(int id, int bit) { return getBitInBitSet(id, bit, FeatureExprFactory.True()); } public static boolean getBitInBitSet(int id, int bit, FeatureExpr ctx) { if (peer != null){ // this is executed if we did run JPF return JPF_gov_nasa_jpf_vm_Verify.getBitInBitSet__II__Z(null, 0, id, bit, ctx); } else { // this is executed if we run this without previously executing JPF checkBitSetId(id); return bitSets[id].get(bit); } } /** * Adds a comment to the error trace, which will be printed and saved. */ public static void addComment (String s) {} /** * Backwards compatibility START * @deprecated use "assert cond : msg" */ @Deprecated public static void assertTrue (String s, boolean cond) { if (!cond) { System.out.println(s); assertTrue(cond); } } /** * Checks that the condition is true. * @deprecated use 'assert' directly */ @Deprecated public static void assertTrue (boolean cond) { if (!cond) { throw new AssertionError("Verify.assertTrue failed"); } } public static void atLabel (String label) {} public static void atLabel (int label) {} /** * Marks the beginning of an atomic block. * THIS IS EVIL, DON'T USE IT FOR OPTIMIZATION - THAT'S WHAT POR IS FOR! * (it's mostly here to support model classes that need to execute atomic) */ public static void beginAtomic () {} /** * Marks the end of an atomic block. * EVIL - see beginAtomic() */ public static void endAtomic () {} public static void boring (boolean cond) {} public static void busyWait (long duration) { // this gets only executed outside of JPF while (duration > 0) { duration--; } } public static boolean isCalledFromClass (String refClsName) { Throwable t = new Throwable(); StackTraceElement[] st = t.getStackTrace(); if (st.length < 3) { // main() or run() return false; } try { Class<?> refClazz = Class.forName(refClsName); Class<?> callClazz = Class.forName(st[2].getClassName()); return (refClazz.isAssignableFrom(callClazz)); } catch (ClassNotFoundException cfnx) { return false; } } public static void ignoreIf (boolean cond) {} public static void instrumentPoint (String label) {} public static void instrumentPointDeep (String label) {} public static void instrumentPointDeepRecur (String label, int depth) {} public static void interesting (boolean cond) {} public static void breakTransition (String reason) {} /** * simple debugging aids to imperatively print the current path output of the SUT * (to be used with vm.path_output) */ public static void printPathOutput(String msg) {} public static void printPathOutput(boolean cond, String msg) {} public static void print (String s) { System.out.print(s); } public static void println (String s) { System.out.println(s); } public static void print (String s, int i) { System.out.print(s + " : " + i); } public static void print (String s, boolean b) { System.out.print(s + " : " + b); } public static void println() { System.out.println(); } /** * this is to avoid StringBuilders */ public static void print (String... args){ for (String s : args){ System.out.print(s); } } /** * note - these are mostly for debugging purposes (to see if attributes get * propagated correctly, w/o having to write a listener), since attributes are * supposed to be created at the native side, and hence can't be accessed from * the application */ //--- use these if you know there are single attributes public static void setFieldAttribute (Object o, String fieldName, int val) {} public static int getFieldAttribute (Object o, String fieldName) { return 0; } //--- use these for multiple attributes public static void addFieldAttribute (Object o, String fieldName, int val) {} public static int[] getFieldAttributes (Object o, String fieldName) { return new int[0]; } public static void setLocalAttribute (String varName, int val) {} public static int getLocalAttribute (String varName) { return 0; } public static void addLocalAttribute (String varName, int val) {} public static int[] getLocalAttributes (String varName) { return new int[0]; } public static void setElementAttribute (Object arr, int idx, int val){} public static int getElementAttribute (Object arr, int idx) { return 0; } public static void addElementAttribute (Object arr, int idx, int val){} public static int[] getElementAttributes (Object arr, int idx) { return new int[0]; } public static void setObjectAttribute (Object o, int val) {} public static int getObjectAttribute (Object o) { return 0; } public static void addObjectAttribute (Object o, int val) {} public static int[] getObjectAttributes (Object o) { return new int[0]; } /** * this is the new boolean choice generator. Since there's no real * heuristic involved with boolean values, we skip the id (it's a * hardwired "boolean") */ public static boolean getBoolean () { // just executed when not running inside JPF, native otherwise return ((System.currentTimeMillis() & 1) != 0); } /** * new boolean choice generator that also tells jpf which value to * use first by default in a search. */ public static boolean getBoolean (boolean falseFirst) { // this is only executed when not running JPF return getBoolean(); } /** * Returns int nondeterministically between (and including) min and max. */ public static int getInt (int min, int max) { // this is only executed when not running JPF, native otherwise return getRandom().nextInt((max-min+1)) + min; } public static int getIntFromList (int... values){ if (values != null && values.length > 0) { int i = getRandom().nextInt(values.length); return values[i]; } else { return getRandom().nextInt(); } } public static Object getObject (String key) { return "?"; } /** * this is the API for int value choice generators. 'id' is used to identify * both the corresponding ChoiceGenerator subclass, and the application specific * ctor parameters from the normal JPF configuration mechanism */ public static int getInt (String key){ // this is only executed when not running JPF, native otherwise return getRandom().nextInt(); } /** * this is the API for double value choice generators. 'id' is used to identify * both the corresponding ChoiceGenerator subclass, and the application specific * ctor parameters from the normal JPF configuration mechanism */ public static double getDouble (String key){ // this is only executed when not running JPF, native otherwise return getRandom().nextDouble(); } public static double getDoubleFromList (double... values){ if (values != null && values.length > 0) { int i = getRandom().nextInt(values.length); return values[i]; } else { return getRandom().nextDouble(); } } public static long getLongFromList (long...values){ if (values != null && values.length > 0) { int i = getRandom().nextInt(values.length); return values[i]; } else { return getRandom().nextLong(); } } public static float getFloatFromList (float...values){ if (values != null && values.length > 0) { int i = getRandom().nextInt(values.length); return values[i]; } else { return getRandom().nextFloat(); } } /** * Returns a random number between 0 and max inclusive. */ public static int random (int max) { // this is only executed when not running JPF return getRandom().nextInt(max + 1); } /** * Returns a random boolean value, true or false. Note this gets * handled by the native peer, and is just here to enable running * instrumented applications w/o JPF */ public static boolean randomBool () { // this is only executed when not running JPF return getRandom().nextBoolean(); } public static long currentTimeMillis () { return System.currentTimeMillis(); } // Backwards compatibility START public static Object randomObject (String type) { return null; } public static boolean isRunningInJPF() { return false; } /** * USE CAREFULLY - returns true if the virtual machine this code is * running under is doing state matching. This can be used as a hint * as to whether data structures (that are known to be correct!) * should be configured to use a canonical representation. For example, * <pre><code> * Vector v = new Vector(); * v.add(obj1); * if (Verify.getBoolean()) { * v.addAll(eleventyBillionObjectCollection); * v.setSize(1); * } * // compare states here * </code></pre> * To the programmer, the states are (almost certainly) the same. To * the VM, they could be different (capacity inside the Vector). For * the sake of speed, Vector does not store things canonically, but this * can cause (probably mild) state explosion if matching states. If * you know whether states are being matched, you can choose the right * structure--as long as those structures aren't what you're looking for * bugs in! */ public static boolean vmIsMatchingStates() { return false; } public static void storeTrace (String fileName, String comment) { // intercepted in NativePeer } public static void storeTraceIf (boolean cond, String fileName, String comment) { if (cond) { storeTrace(fileName, comment); } } public static void storeTraceAndTerminate (String fileName, String comment) { storeTrace(fileName, comment); terminateSearch(); } public static void storeTraceAndTerminateIf (boolean cond, String fileName, String comment) { if (cond) { storeTrace(fileName, comment); terminateSearch(); } } public static boolean isTraceReplay () { return false; // native } public static boolean isShared (Object o){ return false; // native } public static void setShared (Object o, boolean isShared) { // native } public static void freezeSharedness (Object o, boolean freeze) { // native } public static void terminateSearch () { // native } public static void setProperties (String... p) { // native } public static String getProperty (String key) { // native return null; } public static <T> T createFromJSON(Class<T> clazz, String json){ return null; } public static void writeObjectToFile(Object object, String fileName) { try { FileOutputStream fso = new FileOutputStream(fileName); ObjectOutputStream oos = new ObjectOutputStream(fso); oos.writeObject(object); oos.flush(); oos.close(); } catch (Exception ex) { throw new RuntimeException(ex); } } @SuppressWarnings("unchecked") public static <T> T readObjectFromFile(Class<T> clazz, String fileName) { try { FileInputStream fis = new FileInputStream(fileName); try (ObjectInputStream ois = new ObjectInputStream(fis)) { Object read = ois.readObject(); return (T) read; } } catch (Exception ex) { throw new RuntimeException(ex); } } //--- model logging support /* * we add these here so that we don't need to pull in any java.util.logging classes * Note - these need to be kept in sync with our native peer */ public static final int SEVERE = 1; public static final int WARNING = 2; public static final int INFO = 3; public static final int FINE = 4; public static final int FINER = 5; public static final int FINEST = 6; public static void log( String loggerId, int logLevel, String msg){ System.err.println(msg); } // to avoid construction of strings on the model side public static void log( String loggerId, int logLevel, String msg, String arg){ System.err.println(msg); } public static void log( String loggerId, int logLevel, String format, Object... args){ System.err.printf(format, args); } public static void resetInstructionCounter() {} }