Initial commit of analysis before testing through programs!
authoramiraj <amiraj.95@uci.edu>
Thu, 3 Oct 2019 22:53:09 +0000 (15:53 -0700)
committeramiraj <amiraj.95@uci.edu>
Thu, 3 Oct 2019 22:53:09 +0000 (15:53 -0700)
src/main/gov/nasa/jpf/listener/ConflictTracker.java [new file with mode: 0644]

diff --git a/src/main/gov/nasa/jpf/listener/ConflictTracker.java b/src/main/gov/nasa/jpf/listener/ConflictTracker.java
new file mode 100644 (file)
index 0000000..d1efe46
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * 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.listener;
+
+import gov.nasa.jpf.Config;
+import gov.nasa.jpf.JPF;
+import gov.nasa.jpf.ListenerAdapter;
+import gov.nasa.jpf.search.Search;
+import gov.nasa.jpf.jvm.bytecode.*;
+import gov.nasa.jpf.vm.*;
+import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction;
+import gov.nasa.jpf.vm.bytecode.ReadInstruction;
+import gov.nasa.jpf.vm.bytecode.StoreInstruction;
+import gov.nasa.jpf.vm.bytecode.WriteInstruction;
+
+import java.io.PrintWriter;
+
+import java.util.*;
+
+/**
+ * Listener using data flow analysis to find conflicts between smartApps.
+ **/
+
+public class ConflictTracker extends ListenerAdapter {
+
+  private final PrintWriter out;
+  private final HashSet<String> conflictSet = new HashSet<String>(); // Variables we want to track
+  private final HashSet<String> appSet = new HashSet<String>(); // Apps we want to find their conflicts
+  private final HashMap<Integer, ArrayList<Integer>> predSet = new HashMap<Integer, ArrayList<Integer>>();
+  private final HashMap<Integer, ArrayList<Integer>> succSet = new HashMap<Integer, ArrayList<Integer>>();
+  private final HashMap<Integer, DataSet> setSet = new HashMap<Integer, DataSet>();
+  private final HashMap<Integer, DataSet> inSet = new HashMap<Integer, DataSet>();
+  private final HashMap<Integer, DataSet> outSet = new HashMap<Integer, DataSet>();
+  volatile private String operation;
+  volatile private String detail;
+  volatile private int depth;
+  volatile private int id;
+  volatile private int parentId = -2;
+  volatile private int conflictFound = 0;
+  Transition transition;
+  Object annotation;
+  String label;
+  
+  public ConflictTracker(Config conf, JPF jpf) {
+    out = new PrintWriter(System.out, true);
+
+    String[] conflictVars = conf.getStringArray("variables");
+    // We are not tracking anything if it is null
+    if (conflictVars != null) {
+      for (String var : conflictVars) {
+        conflictSet.add(var);
+      }
+    }
+    String[] apps = conf.getStringArray("apps");
+    // We are not tracking anything if it is null
+    if (apps != null) {
+      for (String var : apps) {
+        appSet.add(var);
+      }
+    }
+  }
+
+  class DataList {
+       boolean appSet;
+       String value;
+
+        DataList(boolean appSet, String value) {
+               this.appSet = appSet;
+               this.value = value;
+        }
+  }
+
+  class DataSet {
+       HashMap<Integer, DataList> dataSet = new HashMap<Integer, DataList>();
+
+       DataSet(HashMap<Integer, DataList> dataSet) {
+               this.dataSet = dataSet;
+        }
+  }
+
+  @Override
+  public void stateRestored(Search search) {
+    id = search.getStateId();
+    depth = search.getDepth();
+    operation = "restored";
+    detail = null;
+
+    out.println("The state is restored to state with id: "+id+", depth: "+depth);
+
+    parentId = id;
+  }
+
+  @Override
+  public void searchStarted(Search search) {
+    out.println("----------------------------------- search started");
+  }
+
+  @Override
+  public void stateAdvanced(Search search) {
+    String theEnd = null;
+    id = search.getStateId();
+    depth = search.getDepth();
+    operation = "forward";
+    
+    if (search.isNewState()) {
+      detail = "new";
+    } else {
+      detail = "visited";
+    }
+
+    if (search.isEndState()) {
+      out.println("This is the last state!");
+      theEnd = "end";
+    }
+
+    out.println("The state is forwarded to state with id: "+id+", depth: "+depth+" which is "+detail+" state: "+"% "+theEnd);
+
+
+    //Set input set of this state to empty!
+    HashMap<Integer, DataList> inDataSet = new HashMap<Integer, DataList>();
+    inDataSet.put(0, new DataList(false, "NA"));
+    inDataSet.put(1, new DataList(false, "NA"));
+    DataSet inTempDataSet = new DataSet(inDataSet);
+    inSet.put(id, inTempDataSet);
+    
+    //Set output set of this state to empty if it is not initialized!
+    if (!outSet.containsKey(id)) {
+        HashMap<Integer, DataList> outDataSet = new HashMap<Integer, DataList>();
+        outDataSet.put(0, new DataList(false, "NA"));
+        outDataSet.put(1, new DataList(false, "NA"));
+        DataSet outTempDataSet = new DataSet(outDataSet);
+        outSet.put(id, outTempDataSet);
+    }
+
+    //Create a temp data set of out set of this node
+    DataList tempDataList1 = new DataList(outSet.get(id).dataSet.get(0).appSet, outSet.get(id).dataSet.get(0).value);
+    DataList tempDataList2 = new DataList(outSet.get(id).dataSet.get(1).appSet, outSet.get(id).dataSet.get(1).value);
+    HashMap<Integer, DataList> tempOutDataSet = new HashMap<Integer, DataList>();
+    tempOutDataSet.put(0, tempDataList1);
+    tempOutDataSet.put(1, tempDataList2);
+    DataSet tempDataSet = new DataSet(tempOutDataSet);
+    
+    //Set input set according to output set of pred states of current state
+    if (predSet.containsKey(id)) {
+       for (Integer i : predSet.get(id)) {
+               if ((outSet.get(i).dataSet.get(0).appSet == true)||(inSet.get(id).dataSet.get(0).appSet == true)) {
+                       inSet.get(id).dataSet.get(0).appSet = true;
+                       inSet.get(id).dataSet.get(0).value = outSet.get(i).dataSet.get(0).value;
+               }
+               if ((outSet.get(i).dataSet.get(1).appSet == true)||(inSet.get(id).dataSet.get(1).appSet == true)) {
+                       inSet.get(id).dataSet.get(1).appSet = true;
+                       inSet.get(id).dataSet.get(1).value = outSet.get(i).dataSet.get(1).value;
+               }
+       }
+    }
+
+    //Set output set to inset or setSet
+    if (setSet.containsKey(id)) {
+       if ((setSet.get(id).dataSet.get(0).appSet == true)&&(setSet.get(id).dataSet.get(1).appSet == true)) { //App1 & App2 are writers
+               outSet.get(id).dataSet.get(0).appSet = true;
+               outSet.get(id).dataSet.get(0).value = setSet.get(id).dataSet.get(0).value;
+               outSet.get(id).dataSet.get(1).appSet = true;
+               outSet.get(id).dataSet.get(1).value = setSet.get(id).dataSet.get(1).value;
+       } else if (setSet.get(id).dataSet.get(0).appSet == true) { //App1 is a writer
+               outSet.get(id).dataSet.get(0).appSet = true;
+               outSet.get(id).dataSet.get(0).value = setSet.get(id).dataSet.get(0).value;
+               outSet.get(id).dataSet.get(1).appSet = inSet.get(id).dataSet.get(1).appSet;
+               outSet.get(id).dataSet.get(1).value = inSet.get(id).dataSet.get(1).value;
+       } else if (setSet.get(id).dataSet.get(1).appSet == true) { //App2 is a writer
+               outSet.get(id).dataSet.get(0).appSet = inSet.get(id).dataSet.get(0).appSet;
+                outSet.get(id).dataSet.get(0).value = inSet.get(id).dataSet.get(0).value;
+                outSet.get(id).dataSet.get(1).appSet = true;
+                outSet.get(id).dataSet.get(1).value = setSet.get(id).dataSet.get(1).value;     
+       }
+    } else {
+       outSet.get(id).dataSet.get(0).appSet = inSet.get(id).dataSet.get(0).appSet;
+        outSet.get(id).dataSet.get(0).value = inSet.get(id).dataSet.get(0).value;
+        outSet.get(id).dataSet.get(1).appSet = inSet.get(id).dataSet.get(1).appSet;
+        outSet.get(id).dataSet.get(1).value = inSet.get(id).dataSet.get(1).value;
+    }
+    
+    if ((outSet.get(id).dataSet.get(0).appSet == true)&&(outSet.get(id).dataSet.get(1).appSet == true)) { //Both apps have set the device
+       if (!(outSet.get(id).dataSet.get(0).value.equals(outSet.get(id).dataSet.get(1).value))) //Values set by the apps are not the same, and we have a conflict!
+               conflictFound = 1;
+    }
+
+    if ((outSet.get(id).dataSet.get(0).appSet != tempDataSet.dataSet.get(0).appSet)||
+       ((!outSet.get(id).dataSet.get(0).value.equals(tempDataSet.dataSet.get(0).value)))||
+       (outSet.get(id).dataSet.get(1).appSet != tempDataSet.dataSet.get(1).appSet)||
+       ((!outSet.get(id).dataSet.get(1).value.equals(tempDataSet.dataSet.get(1).value)))) {
+               ArrayList<Integer> changed = new ArrayList<Integer>(predSet.get(id));
+               while(!changed.isEmpty()) {
+                       //Get a random node inside the changed list!
+                       Integer rnd = new Random().nextInt(changed.size());
+                       Integer nodeToProcess  = changed.get(rnd);
+                       changed.remove(nodeToProcess);
+
+                       //Initialize the empty input set for the current node
+                       HashMap<Integer, DataList> nodeDataSet = new HashMap<Integer, DataList>();
+                       nodeDataSet.put(0, new DataList(false, "NA"));
+                       nodeDataSet.put(1, new DataList(false, "NA"));
+                       DataSet nodeTempDataSet = new DataSet(nodeDataSet);
+                       inSet.put(nodeToProcess, nodeTempDataSet);
+
+                       //Store current output to temp dataset
+                       HashMap<Integer, DataList> currentOutDataSet = new HashMap<Integer, DataList>();
+                       currentOutDataSet.put(0, new DataList(outSet.get(nodeToProcess).dataSet.get(0).appSet, outSet.get(nodeToProcess).dataSet.get(0).value));
+                       currentOutDataSet.put(1, new DataList(outSet.get(nodeToProcess).dataSet.get(1).appSet, outSet.get(nodeToProcess).dataSet.get(1).value));
+                       DataSet currentDataSet = new DataSet(currentOutDataSet);
+
+                       //Update the in set based on predecessors
+                       for (Integer i : predSet.get(nodeToProcess)) {
+                               if ((outSet.get(i).dataSet.get(0).appSet == true)||(inSet.get(nodeToProcess).dataSet.get(0).appSet == true)) {
+                                       inSet.get(nodeToProcess).dataSet.get(0).appSet = true;
+                                       inSet.get(nodeToProcess).dataSet.get(0).value = outSet.get(i).dataSet.get(0).value;
+                               }
+
+                               if ((outSet.get(i).dataSet.get(1).appSet == true)||(inSet.get(nodeToProcess).dataSet.get(1).appSet == true)) {
+                                       inSet.get(nodeToProcess).dataSet.get(1).appSet = true;
+                                       inSet.get(nodeToProcess).dataSet.get(1).value = outSet.get(i).dataSet.get(1).value;
+                               }
+                       }
+
+                       //Set output set to inset or setSet
+                       if (setSet.containsKey(nodeToProcess)) {
+                               if ((setSet.get(nodeToProcess).dataSet.get(0).appSet == true)&&(setSet.get(nodeToProcess).dataSet.get(1).appSet == true)) { //App1 & App2 are writers
+                                       outSet.get(nodeToProcess).dataSet.get(0).appSet = true;
+                                       outSet.get(nodeToProcess).dataSet.get(0).value = setSet.get(nodeToProcess).dataSet.get(0).value;
+                                       outSet.get(nodeToProcess).dataSet.get(1).appSet = true;
+                                       outSet.get(nodeToProcess).dataSet.get(1).value = setSet.get(nodeToProcess).dataSet.get(1).value;
+                               } else if (setSet.get(nodeToProcess).dataSet.get(0).appSet == true) { //App1 is a writer
+                                       outSet.get(nodeToProcess).dataSet.get(0).appSet = true;
+                                       outSet.get(nodeToProcess).dataSet.get(0).value = setSet.get(nodeToProcess).dataSet.get(0).value;
+                                       outSet.get(nodeToProcess).dataSet.get(1).appSet = inSet.get(nodeToProcess).dataSet.get(1).appSet;
+                                       outSet.get(nodeToProcess).dataSet.get(1).value = inSet.get(nodeToProcess).dataSet.get(1).value;
+                               } else if (setSet.get(nodeToProcess).dataSet.get(1).appSet == true) { //App2 is a writer
+                                       outSet.get(nodeToProcess).dataSet.get(0).appSet = inSet.get(nodeToProcess).dataSet.get(0).appSet;
+                                       outSet.get(nodeToProcess).dataSet.get(0).value = inSet.get(nodeToProcess).dataSet.get(0).value;
+                                       outSet.get(nodeToProcess).dataSet.get(1).appSet = true;
+                                       outSet.get(nodeToProcess).dataSet.get(1).value = setSet.get(nodeToProcess).dataSet.get(1).value;        
+                               }
+                       } else {
+                               outSet.get(nodeToProcess).dataSet.get(0).appSet = inSet.get(nodeToProcess).dataSet.get(0).appSet;
+                               outSet.get(nodeToProcess).dataSet.get(0).value = inSet.get(nodeToProcess).dataSet.get(0).value;
+                               outSet.get(nodeToProcess).dataSet.get(1).appSet = inSet.get(nodeToProcess).dataSet.get(1).appSet;
+                               outSet.get(nodeToProcess).dataSet.get(1).value = inSet.get(nodeToProcess).dataSet.get(1).value;
+                       }
+                       
+                       //Checking if the output set has changed or not(Add its successors to the change list!)
+                       if ((outSet.get(nodeToProcess).dataSet.get(0).appSet != currentDataSet.dataSet.get(0).appSet)||
+                           !(outSet.get(nodeToProcess).dataSet.get(0).value.equals(currentDataSet.dataSet.get(0).value))||
+                           (outSet.get(nodeToProcess).dataSet.get(1).appSet != currentDataSet.dataSet.get(1).appSet)||
+                           !(outSet.get(nodeToProcess).dataSet.get(1).value.equals(currentDataSet.dataSet.get(1).value))) {
+                               for (Integer i : succSet.get(nodeToProcess))
+                                       if (!changed.contains(i))
+                                               changed.add(i);
+                       }
+                       
+               }
+    }
+    
+    //Update the pred
+    if (succSet.containsKey(id)) {
+       ArrayList<Integer> ids = succSet.get(id);
+       if (!ids.contains(parentId)) {
+               ids.add(parentId);
+               succSet.put(id, ids);
+       }
+    } else if (parentId != -2) {
+       ArrayList<Integer> ids = new ArrayList<Integer>();
+       ids.add(parentId);
+       succSet.put(id, ids);
+    }
+
+    //Update the suc
+    if (succSet.containsKey(parentId)) {
+       ArrayList<Integer> ids = succSet.get(parentId);
+       if (!ids.contains(id)) {
+               ids.add(id);
+               succSet.put(parentId, ids);
+       }
+    } else if (parentId != -2) {
+       ArrayList<Integer> ids = new ArrayList<Integer>();
+       ids.add(id);
+       succSet.put(parentId, ids);
+    }
+
+    parentId = id;
+       
+  }
+
+  @Override
+  public void stateBacktracked(Search search) {
+    id = search.getStateId();
+    depth = search.getDepth();
+    operation = "backtrack";
+    detail = null;
+
+    out.println("The state is backtracked to state with id: "+id+", depth: "+depth);
+
+    parentId = id;
+  }
+
+  @Override
+  public void searchFinished(Search search) {
+    out.println("----------------------------------- search finished");
+  }
+
+  private String getValue(ThreadInfo ti, Instruction inst, byte type) {
+    StackFrame frame;
+    int lo, hi;
+
+    frame = ti.getTopFrame();
+
+    if ((inst instanceof JVMLocalVariableInstruction) ||
+        (inst instanceof JVMFieldInstruction))
+    {
+       if (frame.getTopPos() < 0)
+         return(null);
+
+       lo = frame.peek();
+       hi = frame.getTopPos() >= 1 ? frame.peek(1) : 0;
+
+       return(decodeValue(type, lo, hi));
+    }
+
+    if (inst instanceof JVMArrayElementInstruction)
+      return(getArrayValue(ti, type));
+
+    return(null);
+  }
+
+  private final static String decodeValue(byte type, int lo, int hi) {
+    switch (type) {
+      case Types.T_ARRAY:   return(null);
+      case Types.T_VOID:    return(null);
+
+      case Types.T_BOOLEAN: return(String.valueOf(Types.intToBoolean(lo)));
+      case Types.T_BYTE:    return(String.valueOf(lo));
+      case Types.T_CHAR:    return(String.valueOf((char) lo));
+      case Types.T_DOUBLE:  return(String.valueOf(Types.intsToDouble(lo, hi)));
+      case Types.T_FLOAT:   return(String.valueOf(Types.intToFloat(lo)));
+      case Types.T_INT:     return(String.valueOf(lo));
+      case Types.T_LONG:    return(String.valueOf(Types.intsToLong(lo, hi)));
+      case Types.T_SHORT:   return(String.valueOf(lo));
+
+      case Types.T_REFERENCE:
+        ElementInfo ei = VM.getVM().getHeap().get(lo);
+        if (ei == null)
+          return(null);
+
+        ClassInfo ci = ei.getClassInfo();
+        if (ci == null)
+          return(null);
+
+        if (ci.getName().equals("java.lang.String"))
+          return('"' + ei.asString() + '"');
+
+        return(ei.toString());
+
+      default:
+        System.err.println("Unknown type: " + type);
+        return(null);
+     }
+  }
+
+  private String getArrayValue(ThreadInfo ti, byte type) {
+    StackFrame frame;
+    int lo, hi;
+
+    frame = ti.getTopFrame();
+    lo    = frame.peek();
+    hi    = frame.getTopPos() >= 1 ? frame.peek(1) : 0;
+
+    return(decodeValue(type, lo, hi));
+  }
+
+  private byte getType(ThreadInfo ti, Instruction inst) {
+    StackFrame frame;
+    FieldInfo fi;
+    String type;
+
+    frame = ti.getTopFrame();
+    if ((frame.getTopPos() >= 0) && (frame.isOperandRef())) {
+      return (Types.T_REFERENCE);
+    }
+
+    type = null;
+
+    if (inst instanceof JVMLocalVariableInstruction) {
+      type = ((JVMLocalVariableInstruction) inst).getLocalVariableType();
+    } else if (inst instanceof JVMFieldInstruction){
+      fi = ((JVMFieldInstruction) inst).getFieldInfo();
+      type = fi.getType();
+    }
+
+    if (inst instanceof JVMArrayElementInstruction) {
+      return (getTypeFromInstruction(inst));
+    }
+
+    if (type == null) {
+      return (Types.T_VOID);
+    }
+
+    return (decodeType(type));
+  }
+
+  private final static byte getTypeFromInstruction(Instruction inst) {
+    if (inst instanceof JVMArrayElementInstruction)
+      return(getTypeFromInstruction((JVMArrayElementInstruction) inst));
+
+    return(Types.T_VOID);
+  }
+
+  private final static byte decodeType(String type) {
+    if (type.charAt(0) == '?'){
+      return(Types.T_REFERENCE);
+    } else {
+      return Types.getBuiltinType(type);
+    }
+  }
+
+  // Find the variable writer
+  // It should be one of the apps listed in the .jpf file
+  private String getWriter(List<StackFrame> sfList) {
+    // Start looking from the top of the stack backward
+    for(int i=sfList.size()-1; i>=0; i--) {
+      MethodInfo mi = sfList.get(i).getMethodInfo();
+      if(!mi.isJPFInternal()) {
+        String method = mi.getStackTraceName();
+        // Check against the apps in the appSet
+        for(String app : appSet) {
+          // There is only one writer at a time but we need to always
+          // check all the potential writers in the list
+          if (method.contains(app)) {
+            return app;
+          }
+        }
+      }
+    }
+
+    return null;
+  }
+
+  @Override
+  public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
+    if (conflictFound == 1) {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Conflict found between two apps!");
+      Instruction nextIns = ti.createAndThrowException("java.lang.RuntimeException", sb.toString());
+      ti.setNextPC(nextIns);
+    } else if (executedInsn instanceof WriteInstruction) {
+      String varId = ((WriteInstruction) executedInsn).getFieldInfo().getFullName();
+      for(String var : conflictSet) {
+
+        if (varId.contains(var)) {
+          // Get variable info
+          byte type  = getType(ti, executedInsn);
+          String value = getValue(ti, executedInsn, type);
+          String writer = getWriter(ti.getStack());
+          // Just return if the writer is not one of the listed apps in the .jpf file
+          if (writer == null)
+            return;
+
+         //Update the HashMap for Set set.
+       if (setSet.containsKey(id)) {
+               if (writer.equals("App1")) {
+                       setSet.get(id).dataSet.get(0).appSet = true;
+                       setSet.get(id).dataSet.get(0).value = value;
+               } else if (writer.equals("App2")) {
+                       setSet.get(id).dataSet.get(1).appSet = true;
+                       setSet.get(id).dataSet.get(1).value = value;
+               }                       
+       } else {
+               HashMap<Integer, DataList> dataSet = new HashMap<Integer, DataList>();
+               DataList dataList1 = new DataList(false, "NA");
+               DataList dataList2 = new DataList(false, "NA");         
+               if (writer.equals("App1")) {
+                       dataList1.appSet = true;
+                       dataList1.value = value;
+               } else if (writer.equals("App2")) {
+                       dataList2.appSet = true;
+                       dataList2.value = value;
+               }
+               dataSet.put(0, dataList1);
+               dataSet.put(1, dataList2);
+               DataSet tempDataSet = new DataSet(dataSet);
+               setSet.put(id, tempDataSet);
+       }
+          
+       }
+      }
+
+      
+    }
+  
+  }
+
+}