00001 package gov.nasa.arc.ase.jpf.jvm;
00002
00003 import gov.nasa.arc.ase.jpf.Engine;
00004 import gov.nasa.arc.ase.jpf.ErrorTrailInterface;
00005 import gov.nasa.arc.ase.jpf.InternalErrorException;
00006 import gov.nasa.arc.ase.jpf.JPF;
00007 import gov.nasa.arc.ase.jpf.JPFErrorException;
00008 import gov.nasa.arc.ase.jpf.Path;
00009 import gov.nasa.arc.ase.jpf.Status;
00010 import gov.nasa.arc.ase.jpf.TransitionResult;
00011 import gov.nasa.arc.ase.jpf.iStore;
00012 import gov.nasa.arc.ase.jpf.iScheduler;
00013 import gov.nasa.arc.ase.jpf.iSystemState;
00014 import gov.nasa.arc.ase.jpf.iThreadInfo;
00015 import gov.nasa.arc.ase.jpf.iTrailInfo;
00016 import gov.nasa.arc.ase.jpf.iVirtualMachine;
00017 import gov.nasa.arc.ase.jpf.jvm.reflection.Reflection;
00018 import gov.nasa.arc.ase.util.Comma;
00019 import gov.nasa.arc.ase.util.Counter;
00020 import gov.nasa.arc.ase.util.Debug;
00021 import gov.nasa.arc.ase.util.Right;
00022 import java.io.BufferedReader;
00023 import java.io.FileOutputStream;
00024 import java.io.FileReader;
00025 import java.io.IOException;
00026 import java.io.InputStreamReader;
00027 import java.io.LineNumberReader;
00028 import java.io.OutputStreamWriter;
00029 import java.io.PrintStream;
00030 import java.io.PrintWriter;
00031 import java.lang.reflect.InvocationTargetException;
00032 import java.lang.reflect.Method;
00033 import java.util.Stack;
00034 import java.util.StringTokenizer;
00035 import java.util.Vector;
00036
00037 import edu.ksu.cis.bandera.jjjc.decompiler.FilenameLinePair;
00038
00039
00040
00041
00042
00043
00044
00045 import java.util.LinkedList;
00046
00047
00048 import gov.nasa.arc.ase.jpf.BuchiSet;
00049
00050
00051
00052 import java.util.HashSet;
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 public class VirtualMachine implements iVirtualMachine {
00064
00065
00066
00067 private SystemState ss;
00068
00069
00070
00071
00072 private Stack stateStoringStack;
00073
00074
00075
00076
00077 private Stack stateBacktrackStack;
00078
00079
00080
00081
00082 private Stack backtrackStack;
00083
00084
00085
00086
00087 private boolean maxDepthReached;
00088
00089
00090
00091
00092 private String classname;
00093
00094
00095
00096
00097 private String[] args;
00098
00099
00100
00101
00102 private JVMPath errorPath;
00103
00104
00105
00106
00107 private int posInErrorPath;
00108
00109
00110
00111
00112 private boolean executingPath;
00113
00114
00115
00116
00117 private LinkedList path;
00118
00119
00120
00121
00122
00123
00124
00125 private boolean initialState;
00126
00127
00128
00129
00130 public static HashSet observablePositions = new HashSet();
00131
00132
00133
00134
00135 public static HashSet observableLabels = new HashSet();
00136
00137
00138
00139
00140 public static HashSet observableInvokes = new HashSet();
00141
00142
00143
00144
00145 public static HashSet observableReturns = new HashSet();
00146
00147
00148
00149
00150
00151
00152
00153
00154 public static JVMOptions options;
00155
00156
00157
00158
00159
00160 private static SystemState xss;
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 private static String[] partitionPath = {
00176 null,
00177 "gov.nasa.arc.ase.jpf.partition",
00178 "gov.nasa.arc.ase.jpf.jvm.partition",
00179 };
00180
00181 private static BufferedReader br = new BufferedReader(
00182 new InputStreamReader(System.in));
00183
00184
00185
00186
00187 public VirtualMachine() {
00188 }
00189
00190
00191
00192 public boolean Backtrack() {
00193
00194 if(stateStoringStack.empty())
00195 return false;
00196
00197
00198 Engine.getJPF().store.offStack(ss);
00199
00200
00201 popState();
00202 popSystem();
00203
00204
00205
00206
00207 return true;
00208 }
00209 public boolean BuchiBacktrack() {
00210 return Backtrack();
00211 }
00212 public boolean BuchiEvaluate(Method method) {
00213 Object[] args = new Object[1];
00214 args[0] = ss;
00215
00216 try {
00217 return ((Boolean)method.invoke(null, args)).booleanValue();
00218 } catch(InvocationTargetException e) {
00219 e.printStackTrace();
00220 throw new JPFErrorException("Internal exeception in " + method.getDeclaringClass().getName());
00221 } catch(IllegalAccessException e) {
00222 throw new JPFErrorException("Illegal access to " + method.getDeclaringClass().getName());
00223 }
00224 }
00225 public boolean BuchiEvaluate(Method method, Object[] arg) {
00226 Object[] args = new Object[arg.length+1];
00227
00228 args[0] = ss;
00229 for(int i = 0; i < arg.length; i++) {
00230 if(arg[i] instanceof ReferenceWrapper) {
00231 args[i+1] = getReference(arg[i].toString());
00232 } else
00233 args[i+1] = arg[i];
00234 }
00235
00236 try {
00237 return ((Boolean)method.invoke(null, args)).booleanValue();
00238 } catch(InvocationTargetException e) {
00239 e.printStackTrace();
00240 throw new JPFErrorException("Internal exeception in " + method.getDeclaringClass().getName());
00241 } catch(IllegalAccessException e) {
00242 throw new JPFErrorException("Illegal access to " + method.getDeclaringClass().getName());
00243 }
00244 }
00245
00246 public int BuchiForward() {
00247 boolean sys_move;
00248 int sd = options.search_depth;
00249
00250 if(sd != -1
00251 && stateStoringStack.size() >= sd) {
00252 if(!maxDepthReached) {
00253 maxDepthReached = true;
00254 Debug.println(Debug.WARNING, "Max search depth reached");
00255 }
00256
00257 return TransitionResult.END;
00258 }
00259
00260 JPF jpf = Engine.getJPF();
00261 Status status = jpf.status;
00262
00263 if(status.maxStackDepth < path.size())
00264 status.maxStackDepth = path.size();
00265
00266 pushState();
00267
00268 if(initialState) {
00269 initialState = false;
00270 } else
00271 if(!ss.nextSuccessor()) {
00272 removeState();
00273
00274 return TransitionResult.END;
00275 }
00276
00277 ss.sch.next();
00278 pushSystem();
00279 ss.sch.initialize(ss);
00280
00281
00282
00283 if(options.garbage_collection && ss.GCNeeded) {
00284 ss.ks.gc();
00285 ss.GCNeeded = false;
00286 }
00287
00288
00289
00290 if(ss.violatedAssertion || ss.uncaughtException) {
00291 return TransitionResult.NEW | TransitionResult.ERROR;
00292 } else {
00293 return TransitionResult.NEW;
00294 }
00295 }
00296 public BuchiSet BuchiGet() {
00297 return Engine.getJPF().store.BuchiGet(ss);
00298 }
00299 public void BuchiInitSch() {
00300 ss.sch.initialize(ss);
00301 }
00302 public void BuchiObservable(String observable) {
00303 if(observable.startsWith("invoke.")) {
00304 synchronized(observableInvokes) {
00305 observableInvokes.add(observable.substring(7));
00306 }
00307 } else if(observable.startsWith("return.")) {
00308 synchronized(observableReturns) {
00309 observableReturns.add(observable.substring(7));
00310 }
00311 } else if(observable.startsWith("position.")) {
00312 synchronized(observablePositions) {
00313 observablePositions.add(observable.substring(9));
00314 }
00315 } else if(observable.startsWith("label.")) {
00316 synchronized(observableLabels) {
00317 observableLabels.add(observable.substring(6));
00318 }
00319 } else
00320 Debug.println(Debug.ERROR, "Unknown observable: " + observable);
00321 }
00322 public void BuchiSetState(int buchi_state) {
00323 ((TrailInfo)path.getLast()).setBuchiState(buchi_state);
00324 }
00325
00326
00327
00328 public Path buildPath() {
00329 int s = path.size();
00330
00331 JVMPath p = new JVMPath(s);
00332
00333 for(int index = 0; index < s; index++)
00334 p.set(index, ((TrailInfo)path.get(index)).getEntry());
00335
00336 return p;
00337 }
00338
00339
00340
00341 public FilenameLinePair ErrorBackward() {
00342 Backtrack();
00343
00344 posInErrorPath--;
00345
00346 JVMPathEntry e = errorPath.get(posInErrorPath);
00347
00348 return new FilenameLinePair(e.file, e.line);
00349 }
00350
00351
00352
00353 public FilenameLinePair ErrorForward() {
00354 if (posInErrorPath >= errorPath.size())
00355 return null;
00356
00357 JVMPathEntry e = errorPath.get(posInErrorPath);
00358
00359 Forward();
00360
00361 posInErrorPath++;
00362
00363 if (posInErrorPath >= errorPath.size())
00364 return null;
00365
00366 e = errorPath.get(posInErrorPath);
00367
00368 return new FilenameLinePair(e.file, e.line);
00369 }
00370
00371
00372
00373 public FilenameLinePair ErrorInit() {
00374 reinit();
00375
00376 posInErrorPath = 0;
00377
00378 ss.sch = new PathScheduler(ss, errorPath);
00379
00380 JVMPathEntry e = errorPath.get(posInErrorPath);
00381
00382 return new FilenameLinePair(e.file, e.line);
00383 }
00384
00385
00386
00387 public int ErrorPathLength() {
00388 return errorPath.size();
00389 }
00390 public boolean executePath(Path p) {
00391
00392 int backtrack = p.upCount();
00393 for(int i = 0; i < backtrack; i++)
00394 Backtrack();
00395
00396
00397 executingPath = true;
00398
00399 ss.sch = new PathScheduler(ss, (JVMPath)p);
00400
00401 for(int i = 0; i < p.size(); i++)
00402 Forward();
00403
00404 executingPath = false;
00405 ss.newScheduler();
00406
00407 int result = Engine.getJPF().store.put(this);
00408
00409 return result == iStore.NEW;
00410 }
00411 public boolean executePath(Path p, Object state) {
00412
00413 int backtrack = p.upCount();
00414 for(int i = 0; i < backtrack; i++)
00415 Backtrack();
00416
00417
00418 executingPath = true;
00419
00420 ss.sch = new PathScheduler(ss, (JVMPath)p);
00421
00422 for(int i = 0; i < p.size(); i++)
00423 Forward();
00424
00425 executingPath = false;
00426 ss.newScheduler();
00427
00428 int result = Engine.getJPF().store.put(this);
00429
00430 return result == iStore.NEW;
00431 }
00432
00433
00434
00435 public int Forward() {
00436 int sd = options.search_depth;
00437
00438
00439 if(sd != -1
00440 && stateStoringStack.size() >= sd) {
00441 if(!maxDepthReached) {
00442 maxDepthReached = true;
00443 Debug.println(Debug.WARNING, "Max search depth reached");
00444 }
00445
00446 return TransitionResult.END;
00447 }
00448
00449 JPF jpf = Engine.getJPF();
00450 Status status = jpf.status;
00451
00452 if(status.maxStackDepth < path.size())
00453 status.maxStackDepth = path.size();
00454
00455
00456
00457
00458
00459
00460
00461 pushState();
00462
00463
00464 if(!ss.nextSuccessor()) {
00465
00466 removeState();
00467
00468
00469
00470 return TransitionResult.END;
00471 } else {
00472
00473
00474
00475 if (options.garbage_collection && ss.GCNeeded) {
00476 ss.ks.gc();
00477 ss.GCNeeded = false;
00478 }
00479
00480
00481
00482
00483 ss.sch.next();
00484
00485 if(!executingPath && Engine.options.po_reduction) {
00486 int result = jpf.store.check(ss);
00487
00488
00489 if(ss.sch instanceof POScheduler) {
00490 if(result == iStore.ONSTACK)
00491 ((POScheduler)ss.sch).failedProviso();
00492 }
00493 }
00494
00495
00496 pushSystem();
00497
00498
00499 ss.sch.initialize(ss);
00500
00501 if(ss.ks.isIntermediate()) jpf.status.intermediateTransitions++;
00502
00503 if(ss.violatedAssertion || ss.uncaughtException) {
00504 if(options.no_storing || executingPath || ss.ks.isIntermediate() || jpf.store.put(this) == iStore.NEW)
00505 return TransitionResult.NEW | TransitionResult.ERROR;
00506 else
00507 return TransitionResult.OLD | TransitionResult.ERROR;
00508 } else {
00509 if(options.no_storing || executingPath || ss.ks.isIntermediate() || jpf.store.put(this) == iStore.NEW) {
00510 return TransitionResult.NEW;
00511 }
00512 else
00513 return TransitionResult.OLD;
00514 }
00515 }
00516 }
00517 public Reference getClassReference(String name) {
00518 if(ClassInfo.exists(name))
00519 return ss.ks.sa.get(name);
00520
00521 return null;
00522 }
00523 public String getErrorMessage() {
00524 if(ss.violatedAssertion) return "Assertion violated";
00525 if(ss.uncaughtException) return "Uncaught exception: " + ss.exceptionName;
00526
00527 return "No error found";
00528 }
00529
00530
00531
00532 public ErrorTrailInterface getErrorTrail() {
00533 Vector v = new Vector();
00534
00535 v.addElement("========================");
00536 v.addElement(" *** Path to error: ***");
00537 v.addElement("========================");
00538
00539 int length = path.size();
00540
00541 v.addElement("Steps to error: " + length);
00542
00543 for(int index = 0; index < length; index++)
00544 try {
00545 v.addElement("Step #" + index + " " +
00546 ((TrailInfo)path.get(index)).toString());
00547 } catch(NullPointerException e) {
00548 v.addElement("Step #" + index);
00549 }
00550
00551 ErrorTrail e = new ErrorTrail(v.size());
00552
00553 for(int index = 0; index < v.size(); index++)
00554 e.add((String)v.elementAt(index));
00555
00556 return e;
00557 }
00558
00559
00560
00561 public Path getErrorTrail_from_file() {
00562 JVMPath path = null;
00563 String filename = classname + ".error.path";
00564
00565 try {
00566 LineNumberReader in = new LineNumberReader(
00567 new FileReader(filename));
00568
00569 StringTokenizer t;
00570 String ln = in.readLine();
00571 if(ln != null) {
00572 t = new StringTokenizer(ln, " :\t\r\n");
00573
00574
00575 t.nextToken();
00576 int size = Integer.parseInt(t.nextToken());
00577
00578 path = new JVMPath(size);
00579
00580 for(int index = 0; index < size; index++) {
00581 ln = in.readLine();
00582 t = new StringTokenizer(ln, " :\t\r\n");
00583
00584
00585 t.nextToken();
00586 int thread = Integer.parseInt(t.nextToken());
00587
00588
00589 t.nextToken();
00590 int line = Integer.parseInt(t.nextToken());
00591
00592
00593 t.nextToken();
00594 String classname = t.nextToken();
00595
00596
00597 t.nextToken();
00598 int random = Integer.parseInt(t.nextToken());
00599
00600 path.set(index, new JVMPathEntry(line, classname, thread, random));
00601 }
00602 }
00603 in.close();
00604 } catch (Exception e) {
00605 throw new JPFErrorException("error reading " + filename);
00606 }
00607
00608 return path;
00609 }
00610 public Path getErrorTrail_to_file() {
00611 int length = path.size();
00612
00613 try {
00614 PrintWriter out = new PrintWriter(
00615 new OutputStreamWriter(
00616 new FileOutputStream(classname + ".error.path")));
00617
00618 out.println("Size:" + length);
00619
00620 for(int i = 0; i < length; i++) {
00621 TrailInfo ti = (TrailInfo)path.get(i);
00622
00623
00624 out.println("Thread:" + ti.getThread() + "\t Line:" + ti.getStep(0).line +
00625 "\t Class:" + ti.getStep(0).classname + "\t Random:" + ti.getRandom());
00626 }
00627
00628 out.close();
00629 } catch (IOException e) {
00630 }
00631
00632 return getErrorTrail1();
00633 }
00634
00635
00636
00637 public Path getErrorTrail1() {
00638 int length = path.size();
00639
00640 errorPath = new JVMPath(length);
00641
00642 for(int i = 0; i < length; i++) {
00643 TrailInfo ti = (TrailInfo)path.get(i);
00644 errorPath.set(i, ti.getEntry());
00645 }
00646
00647 return errorPath;
00648 }
00649 public Path getPath(byte[] p) {
00650 return new JVMPath(p);
00651 }
00652 public Reference getReference(String name) {
00653
00654 StringTokenizer st = new StringTokenizer(name, ".");
00655 StringBuffer sb = new StringBuffer();
00656 Reference r = null;
00657
00658 while(st.hasMoreTokens()) {
00659 sb.append(st.nextToken());
00660 if((r = getClassReference(sb.toString())) != null)
00661 break;
00662 sb.append('.');
00663 }
00664
00665 if(r == null)
00666 throw new JPFErrorException("invalid argument: " + name);
00667
00668
00669 while(st.hasMoreTokens()) {
00670 r = r.getObjectField(st.nextToken());
00671 }
00672
00673 return r;
00674 }
00675
00676
00677
00678 public static SystemState getSS() {
00679
00680 return xss;
00681
00682
00683
00684 }
00685 public Object getState() {
00686 return ss.clone();
00687 }
00688
00689
00690
00691 public iSystemState getSystemState() {
00692 return ss;
00693 }
00694
00695
00696
00697
00698
00699
00700 public void init(String[] arguments) {
00701 if(arguments.length == 0)
00702 throw new JPFErrorException("missing class name");
00703
00704 classname = arguments[0];
00705 args = new String[arguments.length-1];
00706 System.arraycopy(arguments, 1, args, 0, args.length);
00707 stateStoringStack = new Stack();
00708 stateBacktrackStack = new Stack();
00709 backtrackStack = new Stack();
00710 setSS(ss = new SystemState(this));
00711 maxDepthReached = false;
00712 errorPath = null;
00713 posInErrorPath = 0;
00714 executingPath = false;
00715 path = new LinkedList();
00716
00717
00718 ClassInfo ci = ClassInfo.getClassInfo(classname);
00719
00720
00721
00722 ss.ks.sa.newClass(ci);
00723
00724
00725 try {
00726 ci.createMainThread(ss, args);
00727 } catch(RuntimeException e) {
00728 ss.ks.jvmError(e, ss.getRunningThread());
00729 }
00730
00731
00732
00733
00734 ss.ks.sa.initializeClasses();
00735
00736
00737 Engine.getJPF().initialized();
00738
00739
00740
00741 if(options.buchi == null)
00742
00743
00744
00745
00746 Engine.getJPF().store.initial(this);
00747
00748
00749
00750 else
00751 initialState = true;
00752
00753
00754 }
00755 public boolean isDeadlocked() {
00756 int length = ss.getThreadCount();
00757 boolean result = false;
00758
00759 for(int i = 0; i < length; i++) {
00760 ThreadInfo th = (ThreadInfo)ss.getThreadInfo(i);
00761 if(th.isRunnable())
00762 return false;
00763 if(th.countStackFrames() != 0)
00764 result = true;
00765 }
00766
00767 return result;
00768 }
00769 public boolean isTerminated() {
00770 return ss.ks.isTerminated();
00771 }
00772
00773
00774
00775 public int nextThreadToExecute() {
00776 if (posInErrorPath >= errorPath.size())
00777 return -1;
00778
00779 JVMPathEntry e = errorPath.get(posInErrorPath);
00780
00781 return e.thread;
00782 }
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835 public void popState() {
00836 int[] storing = (int[])stateStoringStack.pop();
00837 ss.ks.backtrackTo(new ArrayOffset(storing),
00838 stateBacktrackStack.pop());
00839 }
00840 public void popSystem() {
00841 ss.backtrackTo(null, backtrackStack.pop());
00842 path.removeLast();
00843 }
00844
00845
00846
00847 public int previousThreadToExecute() {
00848 if (posInErrorPath < 1)
00849 return -1;
00850
00851 JVMPathEntry e = errorPath.get(posInErrorPath-1);
00852
00853 return e.thread;
00854 }
00855
00856
00857
00858
00859
00860 public void printStackTrace() {
00861 ss.getRunningThread().printStackTrace();
00862 }
00863
00864
00865
00866 public void pushState() {
00867 stateStoringStack.push(ss.ks.getStoringData());
00868 stateBacktrackStack.push(ss.ks.getBacktrackData());
00869 }
00870
00871
00872
00873 public void pushSystem() {
00874 backtrackStack.push(ss.getBacktrackData());
00875 path.addLast(ss.ti);
00876 ss.ti = null;
00877 }
00878
00879
00880
00881 public void reinit() {
00882
00883
00884
00885
00886 StaticMap.reset();
00887
00888
00889 DynamicMap.reset();
00890
00891
00892 stateStoringStack = new Stack();
00893 stateBacktrackStack = new Stack();
00894 backtrackStack = new Stack();
00895 setSS(ss = new SystemState(this));
00896 maxDepthReached = false;
00897 posInErrorPath = 0;
00898 executingPath = false;
00899 path = new LinkedList();
00900
00901 ClassInfo ci = ClassInfo.getClassInfo(classname);
00902 ss.ks.sa.newClass(ci);
00903 ci.createMainThread(ss, args);
00904 ss.ks.sa.initializeClasses();
00905
00906
00907
00908 if(options.buchi == null)
00909
00910
00911
00912 Engine.getJPF().store.initial(this);
00913
00914
00915
00916 else
00917 initialState = true;
00918
00919
00920 }
00921 public void removeState() {
00922 stateStoringStack.pop();
00923 stateBacktrackStack.pop();
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019 private static void setSS(SystemState ss) {
01020
01021 xss = ss;
01022
01023
01024
01025 }
01026
01027
01028
01029 public void setState(Object state) {
01030 ss = (SystemState)((SystemState)state).clone();
01031 ss.vm = this;
01032 setSS(ss);
01033 }
01034
01035
01036
01037 public void ShowErrorTrail() {
01038 ErrorTrailInterface et = getErrorTrail();
01039
01040 et.print();
01041
01042 try{
01043 et.print(new PrintStream(new FileOutputStream("error.trail")));
01044 } catch (IOException e) {
01045 }
01046 }
01047
01048
01049
01050
01051 public void ShowErrorTrail(Path path) {
01052 reinit();
01053
01054 for(int i = 0; i < errorPath.size()-1; i++) {
01055 FilenameLinePair pair = ErrorForward();
01056 Debug.println(Debug.WARNING, pair.getFilename() + " " + pair.getLine());
01057 }
01058 }
01059 public iScheduler xForward(iScheduler sch) {
01060 JPF jpf = Engine.getJPF();
01061 Status status = jpf.status;
01062
01063 if(sch != null)
01064 ss.sch = (Scheduler)sch;
01065 else
01066 ss.sch.initialize(ss);
01067
01068 if(!ss.nextSuccessor())
01069 return null;
01070
01071
01072 if (options.garbage_collection && ss.GCNeeded) {
01073 ss.ks.gc();
01074 ss.GCNeeded = false;
01075 }
01076
01077
01078 ss.sch.next();
01079
01080 sch = (iScheduler)ss.sch.clone();
01081
01082 ss.sch.initialize(ss);
01083
01084 return sch;
01085 }
01086 }