Mercurial > hg > Members > kono > jpf-core
diff src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java Fri Jan 23 10:14:01 2015 -0800 @@ -0,0 +1,345 @@ +/* + * 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.perturb; + +import java.util.Random; +import java.util.Vector; +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.IntChoiceGenerator; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.choice.IntChoiceFromSet; + +/** + * This file implements a generic data abstraction module that can be used + * with the Perturbator to execute a method with a choice of values for the + * method parameters. + * + * This module handles all basic types and selects values for them as follows: + * int, short: random negative integer | 0 | random positive integer + * float: random negative floating point | 0 | random positive floating point + * char: two random values in [0, 255] and an explicit 0 + * boolean: true | false + * + * An instance of this class is expected to be specialized for each method that we + * want perturbed. The cstor creates a vector of valuations for the parameters + * using all choices for each basic type such that each vector can be written + * directly into the method stack frame for parameters + * + */ + +public class GenericDataAbstractor implements OperandPerturbator { + + // A valuations helper class + public class Valuation { + protected int valuation[] = null; + + public Valuation(int size) { + valuation = new int[size]; + } + // create an object from an existing valuation + public Valuation(Valuation seedValuation) { + valuation = seedValuation.valuation.clone(); + } + public Valuation(Valuation val, int size) { + valuation = new int[size]; + int[] valuationArray = val.getValuation(); + for (int i = 0; i < valuationArray.length; i++) + valuation[i] = valuationArray[i]; + } + public int[] getValuation() { + return valuation; + } + public void add(int index, int element) { + valuation[index] = element; + } + } + + static long seed = 5; + + protected MethodInfo mi; + protected StackFrame stackFrame; + protected int nParams; + protected byte[] paramTypes = null; + protected String[] paramTypeNames = null; + protected String[] paramNames = null; + protected Vector<Valuation> valuations = new Vector<Valuation>(); + protected int choices; + protected int operandSize; + protected Valuation valuation = null; + protected boolean isStatic; + protected Random randomizer = new Random(seed); + + public GenericDataAbstractor (Config conf, String keyPrefix){ + // this will expand to read parameters from the configuration + // to specialize the behavior of the abstractor + mi = null; + choices = 0; + } + + // At the time of instance creation we don't have the MethodInfo object + // for the method that needs its parameters perturbed. Therefore, we + // should set MethodInfo using a call to the following method before + // we can use this instance to perturb a method invocation + public void setMethodInfo(MethodInfo m, StackFrame frame) { + if (mi != null) + return; + + mi = m; + stackFrame = frame; + // Need to figure out the right number of parameters. + paramTypes = mi.getArgumentTypes(); + paramTypeNames = mi.getArgumentTypeNames(); + nParams = paramTypes.length; + isStatic = mi.isStatic(); + + // now compute the operand size in 32-bit words + operandSize = 0; + for (byte type : paramTypes) { + if (type == Types.T_LONG || type == Types.T_DOUBLE) + operandSize += 2; + else + operandSize++; + } + + // useful when we call the various populate methods that populate + // choice vectors. The parameter name can be used to specialize + // population to parameter names + paramNames = new String[nParams]; + if (nParams != 0) { + String[] localVars = mi.getLocalVariableNames(); + for (int i = 0; i < nParams; i++) { + paramNames[i] = isStatic? localVars[i] : localVars[i + 1]; + } + } + + // We build an array of choices, with each choice being an index into + // an array of integers representing the operand stack values. + // We then use an IntChoiceGenerator to give us an index that is then + // used to access the values we want to replace for the operands on the + // stack + + valuation = new Valuation(operandSize); + valuations.add(valuation); + populateValuations(frame, 0, 0); + + // we now know how many choices there are and hence set choices + choices = valuations.size() - 1; + } + + // Method to populate boolean values + public int[] populateBoolean(MethodInfo mi, String name) { + int[] bVec = {0 /* false */, 1 /* true */}; + + return bVec; + } + + // Method to populate character values + public int[] populateChar(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 255), 0, Math.abs(randomizer.nextInt() % 255)}; + + return iVec; + } + + // Method to populate byte values + public int[] populateByte(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 128), 0, -1 * Math.abs(randomizer.nextInt() % 127)}; + + return iVec; + } + + // Method to populate integer values + public int[] populateInt(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 100), 0, -1 * Math.abs(randomizer.nextInt() % 100)}; + + return iVec; + } + + // Method to populate integer values + public int[] populateShort(MethodInfo mi, String name) { + return populateInt(mi, name); + } + + // Method to populate long values + public int[] populateLong(MethodInfo mi, String name) { + long[] lVec = {Math.abs(randomizer.nextLong() % 100), 0, -1 * Math.abs(randomizer.nextLong() % 100)}; + int[] iVec = new int[lVec.length * 2]; + + int i = 0; + for (long l : lVec) { + iVec[i++] = Types.hiLong(l); + iVec[i++] = Types.loLong(l); + } + return iVec; + } + + // Method to populate integer values + public int[] populateFloat(MethodInfo mi, String name) { + int[] fVec = {Float.floatToIntBits(randomizer.nextFloat()), 0, + -1 * Float.floatToIntBits(randomizer.nextFloat())}; + + return fVec; + } + + // Method to populate long values + public int[] populateDouble(MethodInfo mi, String name) { + double[] dVec = {-1.414, 0.0, 3.141}; + int[] iVec = new int[dVec.length * 2]; + + int i = 0; + for (double d : dVec) { + iVec[i++] = Types.hiDouble(d); + iVec[i++] = Types.loDouble(d); + } + return iVec; + } + + public void populateValuations(StackFrame frame, int paramIndex, int dataIndex) { + if (paramIndex == nParams) { + // copy the contents of the previous vector as a + // suffix of it will be over-written, retaining + // the valuations for all parameters ahead of the + // suffix + valuation = new Valuation(valuation); + valuations.add(valuation); + } else { + switch (paramTypes[paramIndex]) { + case Types.T_ARRAY: + populateValuations(frame, paramIndex + 1, dataIndex + 1); + break; + case Types.T_BOOLEAN: + int[] bVec = populateBoolean(mi, paramNames[paramIndex]); + for (int i = 0; i < bVec.length; i++) { + valuation.add(dataIndex, bVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_FLOAT: + int[] fVec = populateFloat(mi, paramNames[paramIndex]); + for (int i = 0; i < fVec.length; i++) { + valuation.add(dataIndex, fVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_CHAR: + int[] iVec = populateChar(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_BYTE: + iVec = populateByte(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_INT: + iVec = populateInt(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_SHORT: + iVec = populateShort(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_LONG: + int[] lVec = populateLong(mi, paramNames[paramIndex]); + int i = 0; + while (i < lVec.length) { + valuation.add(dataIndex, lVec[i++]); + valuation.add(dataIndex + 1, lVec[i++]); + populateValuations(frame, paramIndex + 1, dataIndex + 2); + } + break; + case Types.T_DOUBLE: + int[] dVec = populateDouble(mi, paramNames[paramIndex]); + i = 0; + while (i < dVec.length) { + valuation.add(dataIndex, dVec[i++]); + valuation.add(dataIndex + 1, dVec[i++]); + populateValuations(frame, paramIndex + 1, dataIndex + 2); + } + break; + } + } + } + + @Override + public ChoiceGenerator<?> createChoiceGenerator (String id, StackFrame frame, Object refObject) { + // We expect that the refObject in this case will be a MethodInfo object + // Set it so that we can create valuation vectors + assert refObject instanceof MethodInfo : "wrong refObject type for GenericDataAbstractor: " + + refObject.getClass().getName(); + + setMethodInfo((MethodInfo)refObject, frame); + + if (choices > 0) { + // now create a choices vector which will be used to iterate over the number of + // parameter valuations we want to use. We set each element of the vector simply + // to an index into the valuations vector + int[] indices = new int[choices]; + for (int i = 0; i < choices; i++) { + indices[i] = i; + } + return new IntChoiceFromSet(id, indices); + } else + return null; + } + + @Override + public boolean perturb(ChoiceGenerator<?>cg, StackFrame frame) { + assert cg instanceof IntChoiceGenerator : "wrong choice generator type for GenericDataAbstractor: " + cg.getClass().getName(); + + int choice = ((IntChoiceGenerator)cg).getNextChoice(); + Valuation valuation = valuations.get(choice); + + // iterate over the number of operands and set the operand array to the values + // we have in the valuation vector + int val = 0; + + int top = frame.getTopPos(); + int stackIdx = frame.getLocalVariableCount() + ((isStatic)? 0 : 1); + int argSize = paramTypes.length; + + for (int j = 0; j < argSize; j++) { // j ranges over actual arguments + if (!frame.isOperandRef(top - stackIdx)) { + frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false); + if (paramTypes[j] == Types.T_LONG || paramTypes[j] == Types.T_DOUBLE) { + frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false); + } + } + } + + return cg.hasMoreChoices(); + } + + @Override + public Class<? extends ChoiceGenerator<?>> getChoiceGeneratorType(){ + return IntChoiceFromSet.class; + } +}