4d185d00e42617cda0288878623d6ca66e3f3a30
[jpf-core.git] / src / main / gov / nasa / jpf / listener / ConflictTracker.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.listener;
19
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.JPF;
22 import gov.nasa.jpf.ListenerAdapter;
23 import gov.nasa.jpf.search.Search;
24 import gov.nasa.jpf.jvm.bytecode.*;
25 import gov.nasa.jpf.vm.*;
26 import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction;
27 import gov.nasa.jpf.vm.bytecode.ReadInstruction;
28 import gov.nasa.jpf.vm.bytecode.StoreInstruction;
29 import gov.nasa.jpf.vm.bytecode.WriteInstruction;
30
31 import java.io.PrintWriter;
32
33 import java.util.*;
34
35 /**
36  * Listener using data flow analysis to find conflicts between smartApps.
37  **/
38
39 public class ConflictTracker extends ListenerAdapter {
40   private final PrintWriter out;
41   private final HashSet<String> conflictSet = new HashSet<String>(); // Variables we want to track
42   private final HashSet<String> appSet = new HashSet<String>(); // Apps we want to find their conflicts
43   private final HashSet<String> manualSet = new HashSet<String>(); // Writer classes with manual inputs to detect direct-direct(No Conflict) interactions
44   private final HashMap<Integer, Node> nodes = new HashMap<Integer, Node>(); // Nodes of a graph
45   private ArrayList<NameValuePair> tempSetSet = new ArrayList<NameValuePair>();
46   private long timeout;
47   private long startTime;
48   private Node parentNode = new Node(-2);
49   private String operation;
50   private String detail;
51   private String errorMessage;
52   private int depth;
53   private int id;
54   private boolean conflictFound = false;
55   private boolean manual = false;
56
57   private final String SET_LOCATION_METHOD = "setLocationMode";
58   private final String LOCATION_VAR = "locationMode";
59   
60   public ConflictTracker(Config config, JPF jpf) {
61     out = new PrintWriter(System.out, true);
62
63     String[] conflictVars = config.getStringArray("variables");
64     // We are not tracking anything if it is null
65     if (conflictVars != null) {
66       for (String var : conflictVars) {
67         conflictSet.add(var);
68       }
69     }
70     String[] apps = config.getStringArray("apps");
71     // We are not tracking anything if it is null
72     if (apps != null) {
73       for (String var : apps) {
74         appSet.add(var);
75       }
76     }
77     String[] manualClasses = config.getStringArray("manualClasses");
78     // We are not tracking anything if it is null
79     if (manualClasses != null) {
80       for (String var : manualClasses) {
81         manualSet.add(var);
82       }
83     }
84
85     // Timeout input from config is in minutes, so we need to convert into millis
86     timeout = config.getInt("timeout", 0) * 60 * 1000;
87     startTime = System.currentTimeMillis();
88   }
89
90   boolean propagateTheChange(Node currentNode) {
91         HashSet<Node> changed = new HashSet<Node>(currentNode.getSuccessors());
92         HashMap<Node, HashSet<Node>> parentQueueMap = new HashMap<Node, HashSet<Node>>();
93         HashSet<Node> parents = new HashSet<Node>();
94         parents.add(currentNode);
95
96         for (Node node : currentNode.getSuccessors()) {
97                 parentQueueMap.put(node, parents);
98         }
99
100         while(!changed.isEmpty()) {
101                 // Get the first element of the changed set and remove it
102                 Node nodeToProcess = changed.iterator().next();
103                 changed.remove(nodeToProcess);
104
105                 // Update the changed parents
106                 parents = parentQueueMap.get(nodeToProcess);
107                 boolean isChanged = false;
108
109                 for (Node node : parents) {
110                         // Update the edge
111                         isChanged |= updateTheOutSet(node, nodeToProcess);
112                 }
113
114                 // Check for a conflict if the outSet of nodeToProcess is changed
115                 if (isChanged) {
116                         for (Node node : nodeToProcess.getSuccessors()) {
117                                 HashMap<Transition, ArrayList<NameValuePair>> setSets = nodeToProcess.getOutgoingEdges().get(node).getSetSetMap();
118                                 for (Map.Entry mapElement : setSets.entrySet()) {
119                                         Transition transition = (Transition)mapElement.getKey();
120                                         if (checkForConflict(nodeToProcess, node, transition))
121                                                 return true;
122                                 }
123                         }
124                 }
125
126                 // Update the parents list for the successors of the current node
127                 parents = new HashSet<Node>();
128                 parents.add(nodeToProcess);
129
130                 // Checking if the out set has changed or not(Add its successors to the change list!)
131                 if (isChanged) {
132                         for (Node i : nodeToProcess.getSuccessors()) {
133                                 if (!changed.contains(i))
134                                         changed.add(i);
135
136                                 // Update the list of updated parents for the current node
137                                 if (parentQueueMap.containsKey(i))
138                                         parentQueueMap.get(i).add(nodeToProcess);
139                                 else
140                                         parentQueueMap.put(i, parents);
141                         }
142                 }
143       }
144
145       return false;
146   }
147
148   String createErrorMessage(NameValuePair pair, HashMap<String, String> valueMap, HashMap<String, Integer> writerMap) {
149         String message = "Conflict found between the two apps. App"+pair.getAppNum()+
150                          " has written the value: "+pair.getValue()+
151                          " to the variable: "+pair.getVarName()+" while App"
152                          +writerMap.get(pair.getVarName())+" is overwriting the value: "
153                          +valueMap.get(pair.getVarName())+" to the same variable!";
154         System.out.println(message);    
155         return message;
156   }
157
158   boolean checkForConflict(Node parentNode, Node currentNode, Transition currentTransition) {
159         ArrayList<NameValuePair> setSet = parentNode.getOutgoingEdges().get(currentNode).getSetSetMap().get(currentTransition);
160         HashMap<String, String> valueMap = new HashMap<String, String>(); // HashMap from varName to value
161         HashMap<String, Integer> writerMap = new HashMap<String, Integer>(); //  HashMap from varName to appNum
162
163
164         System.out.println("#########################Set Set:");
165         for (int i = 0;i < setSet.size();i++) {
166             NameValuePair nameValuePair = setSet.get(i);
167             String varName = nameValuePair.getVarName();
168             String value = nameValuePair.getValue();
169             Integer appNum = nameValuePair.getAppNum();
170
171             System.out.println("varName="+varName+", value="+value+", appNum="+appNum);
172         }
173         System.out.println("+++++++++++++++++++++++++Out Set:");
174         for (NameValuePair nameValuePair : currentNode.getOutSet()) {
175             String varName = nameValuePair.getVarName();
176             String value = nameValuePair.getValue();
177             Integer appNum = nameValuePair.getAppNum();
178
179             System.out.println("varName="+varName+", value="+value+", appNum="+appNum);
180         }
181
182         // Update the valueMap and writerMap + check for conflict between the elements of setSet
183         for (int i = 0;i < setSet.size();i++) {
184             NameValuePair nameValuePair = setSet.get(i);
185             String varName = nameValuePair.getVarName();
186             String value = nameValuePair.getValue();
187             Integer appNum = nameValuePair.getAppNum();
188
189             if (valueMap.containsKey(varName)) {
190                 // Check if we have a same writer
191                 if (!writerMap.get(varName).equals(appNum)) {
192                         // Check if we have a conflict or not
193                         if (!valueMap.get(varName).equals(value)) {
194                                 errorMessage = createErrorMessage(nameValuePair, valueMap, writerMap);
195                                 return true;
196                         } else { // We have two writers writing the same value
197                                 writerMap.put(varName, 3); // 3 represents both apps
198                         }
199                 } else {
200                         // Check if we have more than one value with the same writer
201                         if (!valueMap.get(varName).equals(value)) {
202                                 // We have one writer writing more than one value in a same event
203                                 valueMap.put(varName, "twoValue");
204                         }
205                 }
206              } else {
207                 valueMap.put(varName, value);
208                 writerMap.put(varName, appNum);
209              }
210         }
211
212         // Check for conflict between outSet and this transition setSet
213         for (NameValuePair i : currentNode.getOutSet()) {
214              if (valueMap.containsKey(i.getVarName())) {
215                  String value = valueMap.get(i.getVarName());
216                  Integer writer = writerMap.get(i.getVarName());
217                      if ((value != null)&&(writer != null)) {
218                          if (!value.equals(i.getValue())&&!writer.equals(i.getAppNum())) { 
219                              // We have different values and different writers
220                              errorMessage = createErrorMessage(i, valueMap, writerMap);
221                              return true;
222                          }
223                      }
224              }
225        }
226
227        return false;
228   }
229
230   boolean updateTheOutSet(Node parentNode, Node currentNode) {
231         HashMap<Transition, ArrayList<NameValuePair>> setSets = parentNode.getOutgoingEdges().get(currentNode).getSetSetMap();
232         HashSet<String> updatedVarNames = new HashSet<String>();
233         Edge currentEdge = parentNode.getOutgoingEdges().get(currentNode);
234         HashMap<String, Integer> lastWriter = currentEdge.getLastWriter();
235         HashMap<String, String> lastValue = currentEdge.getLastValue();
236         HashMap<String, Integer> outSetVarMap = new HashMap<String, Integer>();
237         boolean isChanged = false;
238
239         for (Map.Entry mapElement : setSets.entrySet()) {
240             ArrayList<NameValuePair> setSet = (ArrayList<NameValuePair>)mapElement.getValue();
241   
242             for (int i = 0;i < setSet.size();i++) {
243                         updatedVarNames.add(setSet.get(i).getVarName());
244             }
245         }
246
247
248         for (NameValuePair i : parentNode.getOutSet()) {
249                 outSetVarMap.put(i.getVarName(), i.getAppNum());
250                 if (!updatedVarNames.contains(i.getVarName()))
251                         isChanged |= currentNode.getOutSet().add(i);
252         }
253
254
255         for (Map.Entry mapElement : setSets.entrySet()) {
256             ArrayList<NameValuePair> setSet = (ArrayList<NameValuePair>)mapElement.getValue();
257   
258             for (int i = 0;i < setSet.size();i++) {
259                         String varName = setSet.get(i).getVarName();
260                         Integer writer = lastWriter.get(varName);
261                         String value = lastValue.get(varName);
262
263                         if (setSet.get(i).getAppNum().equals(writer) 
264                             && setSet.get(i).getValue().equals(value)) {
265                                 if (outSetVarMap.containsKey(varName)) {
266                                         Integer hashCode = outSetVarMap.get(varName).hashCode() * 31 +
267                                                            varName.hashCode();
268                                         currentNode.getOutSet().remove(hashCode);
269                                 }
270                                 isChanged |= currentNode.getOutSet().add(setSet.get(i));
271                         }
272             }
273         }
274
275         return isChanged;
276   }
277
278   void updateTheEdge(Node currentNode, Transition transition) {
279         if (parentNode.getOutgoingEdges().containsKey(currentNode)) {
280                 Edge currentEdge = parentNode.getOutgoingEdges().get(currentNode);
281                 if (currentEdge.getSetSetMap().containsKey(transition)) { // Update the transition
282                         if (manual)
283                                 currentEdge.getSetSetMap().put(transition, tempSetSet);
284                         else
285                                 currentEdge.getSetSetMap().get(transition).addAll(tempSetSet);
286                 } else { // Add a new transition
287                         currentEdge.getSetSetMap().put(transition, tempSetSet);
288                 }
289         } else {
290                 parentNode.getOutgoingEdges().put(currentNode, new Edge(parentNode, currentNode));
291                 Edge currentEdge = parentNode.getOutgoingEdges().get(currentNode);
292                 currentEdge.getSetSetMap().put(transition, tempSetSet);
293         }
294
295         // Update the last writer and last value for this edge for each varName
296         Edge currentEdge = parentNode.getOutgoingEdges().get(currentNode);
297         ArrayList<NameValuePair> setSet = currentEdge.getSetSetMap().get(transition);
298         for (int i = 0;i < setSet.size();i++) {
299                 NameValuePair nameValuePair = setSet.get(i);
300                 currentEdge.getLastWriter().put(nameValuePair.getVarName(), nameValuePair.getAppNum());
301                 currentEdge.getLastValue().put(nameValuePair.getVarName(), nameValuePair.getValue());
302         }
303   }
304
305   
306
307   static class Node {
308         Integer id;
309         HashSet<Node> predecessors = new HashSet<Node>();
310         HashSet<Node> successors = new HashSet<Node>();
311         HashSet<NameValuePair> outSet = new HashSet<NameValuePair>();
312         HashMap<Node, Edge> outgoingEdges = new HashMap<Node, Edge>();
313
314         Node(Integer id) {
315           this.id = id;
316         }
317
318         Integer getId() {
319                 return id;
320         }
321
322         HashSet<Node> getPredecessors() {
323                 return predecessors;
324         }
325
326         HashSet<Node> getSuccessors() {
327                 return successors;
328         }
329
330         HashSet<NameValuePair> getOutSet() {
331                 return outSet;
332         }
333
334         HashMap<Node, Edge> getOutgoingEdges() {
335                 return outgoingEdges;
336         }
337   }
338
339   static class Edge {
340         Node source, destination;
341         HashMap<String, Integer> lastWriter = new HashMap<String, Integer>();
342         HashMap<String, String> lastValue = new HashMap<String, String>();
343         HashMap<Transition, ArrayList<NameValuePair>> setSetMap = new HashMap<Transition, ArrayList<NameValuePair>>();
344
345         Edge(Node source, Node destination) {
346                 this.source = source;
347                 this.destination = destination;
348         }
349
350         Node getSource() {
351                 return source;
352         }
353
354         Node getDestination() {
355                 return destination;
356         }
357
358         HashMap<Transition, ArrayList<NameValuePair>> getSetSetMap() {
359                 return setSetMap;
360         }
361
362         HashMap<String, Integer> getLastWriter() {
363                 return lastWriter;
364         }
365
366         HashMap<String, String> getLastValue() {
367                 return lastValue;
368         }
369   }
370
371   static class NameValuePair {
372         Integer appNum;
373         String value;
374         String varName;
375         boolean isManual;
376
377         NameValuePair(Integer appNum, String value, String varName, boolean isManual) {
378                 this.appNum = appNum;
379                 this.value = value;
380                 this.varName = varName;
381                 this.isManual = isManual;
382         }
383
384         void setAppNum(Integer appNum) {
385                 this.appNum = appNum;
386         }
387
388         void setValue(String value) {
389                 this.value = value;
390         }
391
392         void setVarName(String varName) {
393                 this.varName = varName;
394         }
395
396         void setIsManual(String varName) {
397                 this.isManual = isManual;
398         }
399
400         Integer getAppNum() {
401                 return appNum;
402         }
403
404         String getValue() {
405                 return value;
406         }
407
408         String getVarName() {
409                 return varName;
410         }
411
412         boolean getIsManual() {
413                 return isManual;
414         }
415
416         @Override
417         public boolean equals(Object o) {
418       if (o instanceof NameValuePair) {
419         NameValuePair other = (NameValuePair) o;
420         if (varName.equals(other.getVarName()))
421           return appNum.equals(other.getAppNum());
422       }
423       return false;
424         }
425
426         @Override
427         public int hashCode() {
428                 return appNum.hashCode() * 31 + varName.hashCode();
429         }
430   }
431
432   @Override
433   public void stateRestored(Search search) {
434     id = search.getStateId();
435     depth = search.getDepth();
436     operation = "restored";
437     detail = null;
438
439     out.println("The state is restored to state with id: "+id+", depth: "+depth);
440   
441     // Update the parent node
442     if (nodes.containsKey(id)) {
443           parentNode = nodes.get(id);
444     } else {
445           parentNode = new Node(id);
446     }
447   }
448
449   @Override
450   public void searchStarted(Search search) {
451     out.println("----------------------------------- search started");
452   }
453  
454
455   @Override
456   public void stateAdvanced(Search search) {
457     String theEnd = null;
458     Transition transition = search.getTransition();
459     id = search.getStateId();
460     depth = search.getDepth();
461     operation = "forward";
462
463     // Add the node to the list of nodes
464     if (nodes.get(id) == null)
465         nodes.put(id, new Node(id));
466
467     Node currentNode = nodes.get(id);
468
469     // Update the edge based on the current transition
470     updateTheEdge(currentNode, transition);
471
472     // Reset the temporary variables and flags
473     tempSetSet = new ArrayList<NameValuePair>();
474     manual = false;
475
476     // Check for the conflict in this transition
477     conflictFound = checkForConflict(parentNode, currentNode, transition);
478
479     if (search.isNewState()) {
480       detail = "new";
481     } else {
482       detail = "visited";
483     }
484
485     if (search.isEndState()) {
486       out.println("This is the last state!");
487       theEnd = "end";
488     }
489
490     out.println("The state is forwarded to state with id: "+id+", depth: "+depth+" which is "+detail+" state: "+"% "+theEnd);
491     
492     // Updating the predecessors for this node
493     // Check if parent node is already in successors of the current node or not
494     if (!(currentNode.getPredecessors().contains(parentNode)))
495         currentNode.getPredecessors().add(parentNode);
496
497     // Update the successors for this node
498     // Check if current node is already in successors of the parent node or not
499     if (!(parentNode.getSuccessors().contains(currentNode)))
500         parentNode.getSuccessors().add(currentNode);
501
502     // Update the outset of the current node and check if it is changed or not to propagate the change
503     boolean isChanged = updateTheOutSet(parentNode, currentNode);
504     
505     // Check if the outSet of this state has changed, update all of its successors' sets if any
506     if (isChanged) {
507         for (Node node : currentNode.getSuccessors()) {
508                 HashMap<Transition, ArrayList<NameValuePair>> setSets = currentNode.getOutgoingEdges().get(node).getSetSetMap();
509                 for (Map.Entry mapElement : setSets.entrySet()) {
510                         Transition currentTransition = (Transition)mapElement.getKey();
511                         conflictFound = conflictFound || checkForConflict(currentNode, node, currentTransition);
512                 }
513         }
514         conflictFound = conflictFound || propagateTheChange(currentNode);
515     }
516     // Update the parent node
517     if (nodes.containsKey(id)) {
518           parentNode = nodes.get(id);
519     } else {
520           parentNode = new Node(id);
521     }
522   }
523
524   @Override
525   public void stateBacktracked(Search search) {
526     id = search.getStateId();
527     depth = search.getDepth();
528     operation = "backtrack";
529     detail = null;
530
531     out.println("The state is backtracked to state with id: "+id+", depth: "+depth);
532
533     // Update the parent node
534     if (nodes.containsKey(id)) {
535           parentNode = nodes.get(id);
536     } else {
537           parentNode = new Node(id);
538     }
539   }
540
541   @Override
542   public void searchFinished(Search search) {
543     out.println("----------------------------------- search finished");
544   }
545
546   private String getValue(ThreadInfo ti, Instruction inst, byte type) {
547     StackFrame frame;
548     int lo, hi;
549
550     frame = ti.getTopFrame();
551
552     if ((inst instanceof JVMLocalVariableInstruction) ||
553         (inst instanceof JVMFieldInstruction))
554     {
555       if (frame.getTopPos() < 0)
556         return(null);
557
558       lo = frame.peek();
559       hi = frame.getTopPos() >= 1 ? frame.peek(1) : 0;
560
561       return(decodeValue(type, lo, hi));
562     }
563
564     if (inst instanceof JVMArrayElementInstruction)
565       return(getArrayValue(ti, type));
566
567     return(null);
568   }
569
570   private final static String decodeValue(byte type, int lo, int hi) {
571     switch (type) {
572       case Types.T_ARRAY:   return(null);
573       case Types.T_VOID:    return(null);
574
575       case Types.T_BOOLEAN: return(String.valueOf(Types.intToBoolean(lo)));
576       case Types.T_BYTE:    return(String.valueOf(lo));
577       case Types.T_CHAR:    return(String.valueOf((char) lo));
578       case Types.T_DOUBLE:  return(String.valueOf(Types.intsToDouble(lo, hi)));
579       case Types.T_FLOAT:   return(String.valueOf(Types.intToFloat(lo)));
580       case Types.T_INT:     return(String.valueOf(lo));
581       case Types.T_LONG:    return(String.valueOf(Types.intsToLong(lo, hi)));
582       case Types.T_SHORT:   return(String.valueOf(lo));
583
584       case Types.T_REFERENCE:
585         ElementInfo ei = VM.getVM().getHeap().get(lo);
586         if (ei == null)
587           return(null);
588
589         ClassInfo ci = ei.getClassInfo();
590         if (ci == null)
591           return(null);
592
593         if (ci.getName().equals("java.lang.String"))
594           return('"' + ei.asString() + '"');
595
596         return(ei.toString());
597
598       default:
599         System.err.println("Unknown type: " + type);
600         return(null);
601      }
602   }
603
604   private String getArrayValue(ThreadInfo ti, byte type) {
605     StackFrame frame;
606     int lo, hi;
607
608     frame = ti.getTopFrame();
609     lo    = frame.peek();
610     hi    = frame.getTopPos() >= 1 ? frame.peek(1) : 0;
611
612     return(decodeValue(type, lo, hi));
613   }
614
615   private byte getType(ThreadInfo ti, Instruction inst) {
616     StackFrame frame;
617     FieldInfo fi;
618     String type;
619
620     frame = ti.getTopFrame();
621     if ((frame.getTopPos() >= 0) && (frame.isOperandRef())) {
622       return (Types.T_REFERENCE);
623     }
624
625     type = null;
626
627     if (inst instanceof JVMLocalVariableInstruction) {
628       type = ((JVMLocalVariableInstruction) inst).getLocalVariableType();
629     } else if (inst instanceof JVMFieldInstruction){
630       fi = ((JVMFieldInstruction) inst).getFieldInfo();
631       type = fi.getType();
632     }
633
634     if (inst instanceof JVMArrayElementInstruction) {
635       return (getTypeFromInstruction(inst));
636     }
637
638     if (type == null) {
639       return (Types.T_VOID);
640     }
641
642     return (decodeType(type));
643   }
644
645   private final static byte getTypeFromInstruction(Instruction inst) {
646     if (inst instanceof JVMArrayElementInstruction)
647       return(getTypeFromInstruction((JVMArrayElementInstruction) inst));
648
649     return(Types.T_VOID);
650   }
651
652   private final static byte decodeType(String type) {
653     if (type.charAt(0) == '?'){
654       return(Types.T_REFERENCE);
655     } else {
656       return Types.getBuiltinType(type);
657     }
658   }
659
660   // Find the variable writer
661   // It should be one of the apps listed in the .jpf file
662   private String getWriter(List<StackFrame> sfList, HashSet<String> writerSet) {
663     // Start looking from the top of the stack backward
664     for(int i=sfList.size()-1; i>=0; i--) {
665       MethodInfo mi = sfList.get(i).getMethodInfo();
666       if(!mi.isJPFInternal()) {
667         String method = mi.getStackTraceName();
668         // Check against the writers in the writerSet
669         for(String writer : writerSet) {
670           if (method.contains(writer)) {
671             return writer;
672           }
673         }
674       }
675     }
676
677     return null;
678   }
679
680   private void writeWriterAndValue(String writer, String value, String var) {
681     // Update the temporary Set set.
682     NameValuePair temp = new NameValuePair(1, value, var, manual);
683     if (writer.equals("App2"))
684         temp = new NameValuePair(2, value, var, manual);
685     
686     tempSetSet.add(temp);
687   }
688
689   @Override
690   public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
691     if (timeout > 0) {
692       if (System.currentTimeMillis() - startTime > timeout) {
693         StringBuilder sbTimeOut = new StringBuilder();
694         sbTimeOut.append("Execution timeout: " + (timeout / (60 * 1000)) + " minutes have passed!");
695         Instruction nextIns = ti.createAndThrowException("java.lang.RuntimeException", sbTimeOut.toString());
696         ti.setNextPC(nextIns);
697       }
698     }
699
700     if (conflictFound) {
701       StringBuilder sb = new StringBuilder();
702       sb.append(errorMessage);
703       Instruction nextIns = ti.createAndThrowException("java.lang.RuntimeException", sb.toString());
704       ti.setNextPC(nextIns);
705     } else {
706       if (conflictSet.contains(LOCATION_VAR)) {
707         MethodInfo mi = executedInsn.getMethodInfo();
708         // Find the last load before return and get the value here
709         if (mi.getName().equals(SET_LOCATION_METHOD) &&
710                 executedInsn instanceof ALOAD && nextInsn instanceof ARETURN) {
711           byte type  = getType(ti, executedInsn);
712           String value = getValue(ti, executedInsn, type);
713
714           // Extract the writer app name
715           ClassInfo ci = mi.getClassInfo();
716           String writer = ci.getName();
717
718           // Update the temporary Set set.
719           writeWriterAndValue(writer, value, LOCATION_VAR);
720         }
721       } else {
722         if (executedInsn instanceof WriteInstruction) {
723           String varId = ((WriteInstruction) executedInsn).getFieldInfo().getFullName();
724
725           for (String var : conflictSet) {
726             if (varId.contains(var)) {
727               // Get variable info
728               byte type = getType(ti, executedInsn);
729               String value = getValue(ti, executedInsn, type);
730               String writer = getWriter(ti.getStack(), appSet);
731               // Just return if the writer is not one of the listed apps in the .jpf file
732               if (writer == null)
733                 return;
734
735               if (getWriter(ti.getStack(), manualSet) != null)
736                 manual = true;
737
738               // Update the temporary Set set.
739               writeWriterAndValue(writer, value, var);
740             }
741           }
742         }
743       }
744     }
745   }
746 }