2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
18 package gov.nasa.jpf.listener;
20 import gov.nasa.jpf.ListenerAdapter;
21 import gov.nasa.jpf.jvm.bytecode.LCMP;
22 import gov.nasa.jpf.jvm.bytecode.LSUB;
23 import gov.nasa.jpf.jvm.bytecode.NATIVERETURN;
24 import gov.nasa.jpf.vm.ClassInfo;
25 import gov.nasa.jpf.vm.Instruction;
26 import gov.nasa.jpf.vm.StackFrame;
27 import gov.nasa.jpf.vm.VM;
28 import gov.nasa.jpf.vm.MethodInfo;
29 import gov.nasa.jpf.vm.ThreadInfo;
30 import gov.nasa.jpf.vm.choice.IntChoiceFromSet;
34 * a listener that is used to explore all paths from a time-value comparison.
36 * This works by creating a CG on LCMP instructions that involve
37 * System.currentTimeMillis() obtained values, which are attribute tagged
38 * upon return from the native method, propagated on LSUB (duration computation),
39 * and finally used for LCMP interception if the tag attributes are present
41 * long t1 = System.currentTimeMillis();
42 * doSomeComputation();
43 * long t2 = System.currentTimeMillis();
44 * if (t2 - t1 <= MAX_DURATION){
47 * // catastrophic failure branch
50 * which boils down to a bytecode pattern like
52 * invokestatic #2; // System.currentTimeMillis() <<< tag result with TimeVal attr
54 * lsub <<< propagate if any of the operands has a TimeVal attr
56 * lcmp <<< register CG and skip if any of the operands has TimeVal attr
59 public class StopWatchFuzzer extends ListenerAdapter {
61 MethodInfo miCurrentTimeMillis;
63 static class TimeVal {
64 // attribute for values obtained from System.currentTimeMillis()
66 static TimeVal timeValAttr = new TimeVal(); // we don't need separate instances
68 static String CG_ID = "LCMP_fuzzer";
71 public void classLoaded(VM vm, ClassInfo ci){
72 if (miCurrentTimeMillis == null){
73 if (ci.getName().equals("java.lang.System")) {
74 miCurrentTimeMillis = ci.getMethod("currentTimeMillis()J", false); // its got to be there
80 public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){
82 if (executedInsn instanceof NATIVERETURN){
83 if (executedInsn.isCompleted(ti)){
84 if (((NATIVERETURN)executedInsn).getMethodInfo() == miCurrentTimeMillis){
85 // the two top operand slots hold the 'long' time value
86 StackFrame frame = ti.getModifiableTopFrame();
87 frame.addLongOperandAttr( timeValAttr);
94 public void executeInstruction(VM vm, ThreadInfo ti, Instruction insnToExecute){
96 if (insnToExecute instanceof LSUB){ // propagate TimeVal attrs
97 StackFrame frame = ti.getTopFrame();
98 // check if any of the operands have TimeVal attributes
99 // attributes are stored on the first slot of a long val
100 if (frame.hasOperandAttr(1, TimeVal.class) || frame.hasOperandAttr(3, TimeVal.class)){
101 // enter insn (this pops the 4 top operand slots and pushes the long result
102 ti.skipInstruction(insnToExecute.execute(ti));
104 // propagate TimeVal attr, now we need a modifiable frame
105 frame = ti.getModifiableTopFrame();
106 frame.addLongOperandAttr(timeValAttr);
109 } else if (insnToExecute instanceof LCMP){ // create and set CG if operand has TimeVal attr
111 if (!ti.isFirstStepInsn()){ // this is the first time we see this insn
112 StackFrame frame = ti.getTopFrame();
114 if (frame.hasOperandAttr(1, TimeVal.class) || frame.hasOperandAttr(3, TimeVal.class)){
115 IntChoiceFromSet cg = new IntChoiceFromSet( CG_ID, -1, 0, 1);
116 if (vm.setNextChoiceGenerator(cg)){
117 ti.skipInstruction(insnToExecute); // reexecute after breaking the transition
121 } else { // it is the beginning of a transition, push the choice and proceed
122 IntChoiceFromSet cg = vm.getCurrentChoiceGenerator(CG_ID, IntChoiceFromSet.class);
124 int choice = cg.getNextChoice();
125 StackFrame frame = ti.getModifiableTopFrame();
133 ti.skipInstruction(insnToExecute.getNext());