package cute.concolic.input; import cute.concolic.Call; import cute.concolic.Globals; import cute.concolic.Information; import cute.concolic.generateinputandschedule.PointerSolver; import cute.concolic.logging.ExecutionLog; import cute.concolic.logging.JUnitTestGenerator; import cute.concolic.logging.Logger; import cute.concolic.logging.Printable; import cute.concolic.symbolicstate.*; import cute.instrument.SymbolTable; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Random; import java.util.Vector; /** * Author: Koushik Sen <ksen@cs.uiuc.edu> */ public class InputMap implements Printable { public InputElement input=null; public InputElement currInput = null; private InputElement prevInput = null; public Vector symbolicArithInputValue; private Information information; private Logger logger; private JUnitTestGenerator junitTest; private State state; private ExecutionLog ptrace; private SymbolTable st; private Random rand; public InputMap(Information information, Logger logger, JUnitTestGenerator junitTest, State state, ExecutionLog ptrace, SymbolTable st, Random rand) { this.information = information; this.logger = logger; this.junitTest = junitTest; this.state = state; this.ptrace = ptrace; this.st = st; this.rand = rand; } public int nSymbolicArithInputValues(){ return symbolicArithInputValue.size(); } public int putAndGetArithExpression(InputElement val) { int x = nSymbolicArithInputValues()+1; symbolicArithInputValue.add(val); return x; } public void updateArithInput(int j, double v) { InputElement tmp = (InputElement)(symbolicArithInputValue.get(j-1)); if(tmp.val instanceof FunctionExpression){ ((FunctionExpression)tmp.val).solve(v,this); } else { switch(tmp.type){ case Globals.INT: tmp.val = new Integer((int)(v+(v>0.1?0.2:-0.2))); break; case Globals.SHORT: tmp.val = new Short((short)(v+(v>0.1?0.2:-0.2))); break; case Globals.LONG: tmp.val = new Long((long)(v+(v>0.1?0.2:-0.2))); break; case Globals.BYTE: tmp.val = new Byte((byte)(v+(v>0.1?0.2:-0.2))); break; case Globals.CHAR: tmp.val = new Character((char)(v+(v>0.1?0.2:-0.2))); break; case Globals.BOOLEAN: tmp.val = new Boolean(v>0.5); break; case Globals.FLOAT: tmp.val = new Float((float)v); break; case Globals.DOUBLE: tmp.val = new Double((double)v); break; } } } public double getArithInput(int j) { InputElement tmp = (InputElement)(symbolicArithInputValue.get(j-1)); switch(tmp.type){ case Globals.INT: return ((Integer)tmp.val).doubleValue(); case Globals.SHORT: return ((Short)tmp.val).doubleValue(); case Globals.LONG: return ((Long)tmp.val).doubleValue(); case Globals.BYTE: return ((Byte)tmp.val).doubleValue(); case Globals.CHAR: return ((Character)tmp.val).charValue(); case Globals.BOOLEAN: return ((Boolean)tmp.val).booleanValue()?1.0:0.0; case Globals.FLOAT: return ((Float)tmp.val).doubleValue(); case Globals.DOUBLE: return ((Double)tmp.val).doubleValue(); } System.exit(1); return 0.0; } public int symbolicArithInputType(int i) { return ((InputElement)(symbolicArithInputValue.get(i-1))).type; } public Vector symbolicPointerInputValue; public int nSymbolicPointerInputValues(){ return symbolicPointerInputValue.size(); } public int putAndGetPointerExpression(InputElement val) { int x = nSymbolicPointerInputValues()+1; symbolicPointerInputValue.add(val); return x; } public InputElement getPointerElement(int i) { return (InputElement)(symbolicPointerInputValue.get(i-1)); } public void updatePointerInput(PointerSolver ps,int s, int b, boolean isEq) { int i; int s_points_to = s; int b_points_to = b; if (isEq) { if (s_points_to==0) { getPointerElement(b_points_to).val = null; } else if (getPointerElement(s_points_to).val == null) { if (ps.isEqual(s,0)) { for (i=1;i<ps.nodes.length;i++) { if (ps.isEqual(b,i)) { b_points_to = i; getPointerElement(b_points_to).val = null; } } } else { getPointerElement(s_points_to).val = getPointerElement(b_points_to).val; } } else if (getPointerElement(b_points_to).val == null) { if (ps.isEqual(b,0)) { for (i=1;i<ps.nodes.length;i++) { if (ps.isEqual(s,i)) { s_points_to = i; getPointerElement(s_points_to).val = null; } } } else { getPointerElement(b_points_to).val = getPointerElement(s_points_to).val; } } else { for (i=1;i<ps.nodes.length;i++) { if (ps.isEqual(b,i)) { b_points_to = i; getPointerElement(b_points_to).val = getPointerElement(s_points_to).val; } } System.err.println("Making two non-NULL pointers equal"); } } else { if (s_points_to==0) { getPointerElement(b_points_to).val = Dumbo.val; } else if (getPointerElement(s_points_to).val == null) { if (ps.isEqual(s,0)) { getPointerElement(b_points_to).val = Dumbo.val; } else { getPointerElement(s_points_to).val = Dumbo.val; } } else if (getPointerElement(b_points_to).val == null) { if (ps.isEqual(b,0)) { getPointerElement(s_points_to).val = Dumbo.val; } else { getPointerElement(b_points_to).val = Dumbo.val; } } else { getPointerElement(b_points_to).val = Dumbo.val; System.err.println("Making two non-NULL pointers unequal"); } } } public void read() { cute.concolic.ObjectInput in = new cute.concolic.ObjectInput("Inputs",true,information); Vector tmp = new Vector(); symbolicArithInputValue = new Vector(); symbolicPointerInputValue = new Vector(); if(in.ok()){ InputElement elt; try { int sz = in.in.readInt(); for(int i=0;i<sz;i++){ elt = (InputElement)in.in.readObject(); elt.id=tmp.size(); tmp.add(elt); } } catch (IOException e) { e.printStackTrace(); System.exit(1); } catch(ClassNotFoundException e2){ e2.printStackTrace(); System.exit(1); } for (Iterator iterator = tmp.iterator(); iterator.hasNext();) { InputElement inputElement = (InputElement) iterator.next(); if(inputElement.type==Globals.REFERENCE){ if(inputElement.val!=null && inputElement.val instanceof ReferenceObject){ inputElement.val = tmp.get(((ReferenceObject)inputElement.val).val); } else if(inputElement.val!=null && inputElement.val instanceof Dumbo){ inputElement.val = Dumbo.val; } } if(inputElement.next!=null && inputElement.next instanceof ReferenceObject){ inputElement.next = tmp.get(((ReferenceObject)inputElement.next).val); } } prevInput = null; currInput = input = (InputElement)tmp.get(0); if((information.debugLevel&4)!=0) logger.info(4,null,this); in.close(); } else { prevInput = currInput = input = null; } } private void linearizeInput(IdentityHashMap seen, Vector v, InputElement elt){ InputElement tmp = elt; while(tmp!=null){ v.add(tmp); seen.put(tmp,tmp); tmp.id = v.size()-1; if(tmp.val instanceof InputElement && !seen.containsKey(tmp.val)){ linearizeInput(seen, v,(InputElement)tmp.val); } tmp = (InputElement)tmp.next; } } public void write(){ if(input==null) return; cute.concolic.ObjectOutput out = new cute.concolic.ObjectOutput("Inputs"); if(out.ok()){ Vector arr = new Vector(); IdentityHashMap seen = new IdentityHashMap(); linearizeInput(seen,arr,input); try { out.out.writeInt(arr.size()); for (Iterator iterator = arr.iterator(); iterator.hasNext();) { InputElement inputElement = (InputElement) iterator.next(); out.out.writeObject(inputElement.makeSerializable()); } } catch(IOException e2){ e2.printStackTrace(); System.exit(1); } out.close(); } } public void print(PrintWriter out){ Vector arr = new Vector(); IdentityHashMap seen = new IdentityHashMap(); linearizeInput(seen,arr,input); out.println("-------------------"); out.println("Input"); out.println("-------------------"); for (Iterator iterator = arr.iterator(); iterator.hasNext();) { InputElement inputElement = (InputElement) iterator.next(); inputElement.print(out); } out.println("-------------------"); out.flush(); } public boolean isInputAvailable(int type) { if(currInput==null) return false; if(currInput.type!=type){ currInput = null; return false; //System.err.println("CUTE: input seems to be corrupted"); //System.exit(1); } return true; } /** * Inserts val in the list {@link #input} by creating a new {@link InputElement} object. * {@link #prevInput} points to the newly created object. * {@link #currInput} is always set to null. * {@link #input} points to the head of the list. * @param val * @param type * @return the new created object. */ public InputElement setInput(Object val,int type) { InputElement elt = new InputElement(); elt.next = null; elt.type = type; elt.val = val; if(prevInput!=null){ prevInput.next = elt; } prevInput = elt; currInput = null; if(input==null){ input = elt; } return elt; } public void pushCurrInput(InputElement elt) { prevInput = null; if(elt.val == Dumbo.val) { currInput = null; } else { currInput = (InputElement)elt.val; } } public void popCurrInput(InputElement elt) { this.prevInput = elt; this.currInput = (InputElement)elt.next; } public InputElement getInput() { prevInput = currInput; currInput = (InputElement)currInput.next; return prevInput; } private IdentityHashMap initialized = new IdentityHashMap(); public boolean isAlreadyInitialized(InputElement inputElement) { return initialized.containsKey(inputElement); } public Object getInitialized(InputElement inputElement) { return initialized.get(inputElement); } public void setInitialized(InputElement inputElement, Object ret) { initialized.put(inputElement,ret); } public Object ObjectAux(String className,boolean recursive){ Class c = null; junitTest.assignToInput(className); if((information.debugLevel&1)!=0) logger.info(1,"Input Class Begin",null); try { c = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Object tmp = input(c,0,recursive); chooseNullAndNonullValues(tmp); if((information.debugLevel&1)!=0) logger.info(1,"Input Class End",null); return tmp; } final static int SOMELOCALVAR = 2; final static int NOLINENUMBER = -1; private void chooseNullAndNonullValues(Object tmp){ Call.loadAddress(0,SOMELOCALVAR,NOLINENUMBER); Call.loadValue(tmp,NOLINENUMBER); Call.loadValue(null,NOLINENUMBER); Call.applyOp("==",NOLINENUMBER); if(tmp==null) Call.branchPos(null,-1,-1,NOLINENUMBER); else Call.branchNeg(null,-1,-1,NOLINENUMBER); } private void pushExpression(Expression e){ state.setState(SOMELOCALVAR,e); Call.popAll(NOLINENUMBER); Call.setReturn(0,SOMELOCALVAR,NOLINENUMBER); } private Object initializeInputObjectToRet(String className,InputElement val,Object ret){ if(information.printTraceAndInputs){ ptrace.printInputLn(System.identityHashCode(ret)+"("+className+")"); } if(ret == null) junitTest.valueObjectNull(); else junitTest.valueObject(System.identityHashCode(ret),className); pushExpression(new PointerExpression(putAndGetPointerExpression(val))); return ret; } private void initializeInputObjectFields(Class c,Object ret,int tab,String varName,boolean recursive){ Field[] field = c.getFields(); for (int i = 0; i < field.length; i++) { Field field1 = field[i]; try { int mod = field1.getModifiers(); if(!Modifier.isPrivate(mod) && !Modifier.isProtected(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)){ String type = field1.getType().toString(); if(information.printTraceAndInputs){ for(int l=0;l<tab+1;l++) ptrace.printInput(" "); ptrace.printInput(field1.getName()); ptrace.printInput("="); } if(!type.startsWith("class")){ junitTest.assignTo(varName,field1.getName(),type); } Call.funBegin(null,NOLINENUMBER); if(type.equals("int")){ field1.setInt(ret,((Integer)myInputWithoutAssignTo(Globals.INT, null)).intValue()); } else if(type.equals("short")){ field1.setShort(ret,((Short)myInputWithoutAssignTo(Globals.SHORT, null)).shortValue()); } else if(type.equals("byte")) { field1.setByte(ret,((Byte)myInputWithoutAssignTo(Globals.BYTE, null)).byteValue()); } else if(type.equals("char")) { field1.setChar(ret,((Character)myInputWithoutAssignTo(Globals.CHAR, null)).charValue()); } else if(type.equals("long")){ field1.setLong(ret,((Long)myInputWithoutAssignTo(Globals.LONG, null)).longValue()); } else if(type.equals("boolean")){ field1.setBoolean(ret,((Boolean)myInputWithoutAssignTo(Globals.BOOLEAN, null)).booleanValue()); } else if(type.equals("float")){ field1.setFloat(ret,((Float)myInputWithoutAssignTo(Globals.FLOAT, null)).floatValue()); } else if(type.equals("double")){ field1.setDouble(ret,((Double)myInputWithoutAssignTo(Globals.DOUBLE, null)).doubleValue()); } else if(type.startsWith("class")){ junitTest.assignTo(varName,field1.getName(),type.substring(6)); field1.set(ret,input(field1.getType(),tab+1,recursive)); } Call.funEnd(NOLINENUMBER); Call.storeReturn(ret,st.get(field1.getName()),NOLINENUMBER); } } catch (IllegalAccessException e) { e.printStackTrace(); System.exit(1); } } } private void exitIfNonInstantiable(Class c){ int cmod = c.getModifiers(); if(Modifier.isAbstract(cmod) || Modifier.isInterface(cmod)){ System.err.println("CUTE: Input type is not instantiable"); System.exit(1); } } private Object newInstance(Class c){ Object ret = CustomInitializer.getNewInstance(c,information.random,rand); if(ret==null){ try { return c.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. System.exit(1); } catch (IllegalAccessException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. System.exit(1); } } return ret; } private Object input(Class c,int tab,boolean recursive){ Object ret=null; InputElement val; String varName=null; exitIfNonInstantiable(c); if(!isInputAvailable(Globals.REFERENCE)){ val = setInput(ret,Globals.REFERENCE); return initializeInputObjectToRet(c.getName(),val,ret); } val = getInput(); if(val.val==null){ return initializeInputObjectToRet(c.getName(),val,ret); } if(val.val != Dumbo.val && isAlreadyInitialized((InputElement)val.val)){ ret = getInitialized((InputElement)val.val); return initializeInputObjectToRet(c.getName(),val,ret); } pushCurrInput(val); Object o = null; if (val.val == Dumbo.val) { ret = newInstance(c); o = AnyObject.val; myInput(Globals.OBJECT, o); } else if (!(val.val instanceof InputElement)) { ret = val.val; o = ret; myInput(Globals.OBJECT, o); } else if (((InputElement) val.val).val instanceof AnyObject) { ret = newInstance(c); o = AnyObject.val; myInput(Globals.OBJECT, o); } else { ret = ((InputElement) val.val).val; o = ret; myInput(Globals.OBJECT, o); } val.val = prevInput; setInitialized((InputElement) val.val, ret); if (information.printTraceAndInputs) { if (o instanceof AnyObject) ptrace.printInputLn(System.identityHashCode(ret) + "(" + c.getName() + ")"); else ptrace.printInputLn(ret + "(" + c.getName() + ")"); } if (o instanceof AnyObject) varName = junitTest.valueObject(System.identityHashCode(ret), c.getName()); else varName = junitTest.valueObject(System.identityHashCode(ret), c.getName(), ret); if(recursive) initializeInputObjectFields(c,ret,tab,varName,recursive); popCurrInput(val); Expression e = new PointerExpression(putAndGetPointerExpression(val)); state.setStateConcrete(new Long(System.identityHashCode(ret)),e); pushExpression(e); return ret; } Object myInput(int type, Object o){ switch(type){ case Globals.INT: junitTest.assignToInput("Integer"); break; case Globals.SHORT: junitTest.assignToInput("Short"); break; case Globals.LONG: junitTest.assignToInput("Long"); break; case Globals.BYTE: junitTest.assignToInput("Byte"); break; case Globals.CHAR: junitTest.assignToInput("Character"); break; case Globals.FLOAT: junitTest.assignToInput("Float"); break; case Globals.DOUBLE: junitTest.assignToInput("Double"); break; case Globals.BOOLEAN: junitTest.assignToInput("Boolean"); break; } return myInputWithoutAssignTo(type, o); } private Object myInputWithoutAssignTo(int type, Object o) { Object ret; InputElement val; if((information.debugLevel&1)!=0) logger.info(1,"myInput Begin",null); if(isInputAvailable(type)){ val = getInput(); ret = val.val; } else { if(information.random){ ret = nextRandom(type,o); } else { ret = nextDefault(type,o); } val = setInput(ret,type); } if((information.debugLevel&1)!=0) logger.info(1,"myInput End",null); if(information.printTraceAndInputs && (type != Globals.OBJECT )){ ptrace.printInputLn(ret+"("+ret.getClass().getName().substring(10).toLowerCase()+")"); } if(type!=Globals.OBJECT ){ junitTest.valuePrimitive(ret); pushExpression(new ArithmeticExpression(putAndGetArithExpression(val))); } return ret; } private Object nextDefault(int type,Object o) { switch(type){ case Globals.INT: return new Integer(0); case Globals.SHORT: return new Short((short) 0); case Globals.LONG: return new Long(0); case Globals.BYTE: return new Byte((byte) 0); case Globals.CHAR: return new Character((char) 0); case Globals.FLOAT: return new Float(0.0); case Globals.DOUBLE: return new Double(0.0); case Globals.BOOLEAN: return new Boolean(false); case Globals.OBJECT: return o; } System.err.println("Control flow should not reach this point"); System.exit(1); return null; } private Object nextRandom(int type,Object o) { switch(type){ case Globals.INT: return new Integer(rand.nextInt()); case Globals.SHORT: return new Short((short)rand.nextInt()); case Globals.LONG: return new Long(rand.nextLong()); case Globals.BYTE: return new Byte((byte)rand.nextInt()); case Globals.CHAR: return new Character((char)rand.nextInt()); case Globals.FLOAT: return new Float(rand.nextFloat()); case Globals.DOUBLE: return new Double(rand.nextDouble()); case Globals.BOOLEAN: return new Boolean(rand.nextBoolean()); case Globals.OBJECT: return o; } System.err.println("Control flow should not reach this point"); System.exit(1); return null; } }