/* * Created on Oct 27, 2004 */ package fr.lifl.stc.stan.execution; import java.util.ArrayList; import org.apache.bcel.Constants; import org.apache.bcel.generic.ACONST_NULL; import org.apache.bcel.generic.ATHROW; import org.apache.bcel.generic.ArrayType; import org.apache.bcel.generic.BasicType; import org.apache.bcel.generic.ArithmeticInstruction; import org.apache.bcel.generic.ArrayInstruction; import org.apache.bcel.generic.BranchInstruction; import org.apache.bcel.generic.ExceptionThrower; import org.apache.bcel.generic.FieldInstruction; import org.apache.bcel.generic.ConversionInstruction; import org.apache.bcel.generic.INSTANCEOF; import org.apache.bcel.generic.INVOKESTATIC; import org.apache.bcel.generic.INVOKESPECIAL; import org.apache.bcel.generic.Instruction; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InvokeInstruction; import org.apache.bcel.generic.LocalVariableInstruction; import org.apache.bcel.generic.MULTIANEWARRAY; import org.apache.bcel.generic.NEW; import org.apache.bcel.generic.RET; import org.apache.bcel.generic.ReferenceType; import org.apache.bcel.generic.Select; import org.apache.bcel.generic.StackInstruction; import org.apache.bcel.generic.Type; import org.apache.bcel.generic.TypedInstruction; import fr.lifl.stc.stan.analyser.Config; import fr.lifl.stc.stan.analyser.MethodAnalyzer; import fr.lifl.stc.stan.analyser.Stats; import fr.lifl.stc.stan.execution.stack.Address; import fr.lifl.stc.stan.execution.stack.ExecutionStack; import fr.lifl.stc.stan.execution.stack.JvmType; import fr.lifl.stc.stan.execution.stack.MultiObject; import fr.lifl.stc.stan.execution.stack.Reference; import fr.lifl.stc.stan.execution.stack.Value; import fr.lifl.stc.stan.policy.Policy; import fr.lifl.stc.stan.signature.Signature; import fr.lifl.stc.stan.signature.SignatureDictionary; import fr.lifl.stc.stan.util.Printer; /** * @author yann * @author dorina */ public class Interpreter { private MethodAnalyzer analyzer; private Policy policy; private int line; private Reference[] refs; private Address[] addresses; private Value[] values; private JvmType[] refValues; public int refValuesLength; private Frame default_frame; private MethodInfo meth; private Reference constant_ref; // special ref for constant pool entries private Reference null_ref; // special ref for null entry private Reference exception_ref; private Reference flux_ref; // special ref for flux entries /** * a signature is final is the method does not invoke other methods, or if all the invoked methods are final */ private boolean isFinal; public Interpreter(MethodAnalyzer analyzer) { //we suppose the method is final. While finding an invoke, if the used signature is not final, //the value of final will be changed this.isFinal = true; this.analyzer = analyzer; policy = analyzer.getPolicy(); meth = analyzer.getMethodInfo(); //new MethodInfo(analyzer); refs = meth.getReferences(); addresses = meth.getAddresses(); values = meth.getValues(); refValues = meth.getJvmValues(); // refValues = new JvmType[values.length+refs.length]; // for(int i = 0; i < refs.length; i++) { // refValues[i] = refs[i]; // refs[i].setIndex(i); // } // for(int i = 0; i < values.length; i++) { // refValues[i+refs.length] = values[i]; // values[i].setIndex(i+refs.length); // } this.refValuesLength = refValues.length; // find the constant ref for(int i = 0; i < refs.length; i++) { if(refs[i].isConstant()) { constant_ref = refs[i]; break; } } //find the null ref for(int i = 0; i < refs.length; i++) { if(refs[i].isNull()) { null_ref = refs[i]; break; } } for(int i = 0; i < refs.length; i++) { if(refs[i].isThrown()) { exception_ref = refs[i]; break; } } for(int i = 0; i < refs.length; i++) { if(refs[i].isFlux()) { flux_ref = refs[i]; break; } } default_frame = new Frame(this); int nb_locals = analyzer.getMethod().getCode().getMaxLocals(); MultiObject[] localvars = new MultiObject[nb_locals]; for(int i = 0; i < nb_locals; i++) { localvars[i] = new MultiObject(); } int real_index = 0; Type[] arg_types = analyzer.getMethod().getArgumentTypes(); // add this if it exists if(!analyzer.getMethod().isStatic()) { localvars[real_index++].add(findArgument(-1)); } for (int i = 0; i < arg_types.length; i++, real_index++) { // put argument in corresponding local //TODO change localvars[real_index].add(findArgument(i)); if (arg_types[i].getSize() == 2){ real_index++; localvars[real_index].add(findArgument(i)); } } default_frame.saveVariablesArray(localvars); // push the initial reference for static world default_frame.getStaticWorld().add(findArgument(-2)); default_frame.getException().add(exception_ref); default_frame.getFlux().add(flux_ref); // TODO: initialize dependencies for arguments? // for(int i = 0; i < arg_types.length; i++) { // default_frame.makePointTo(localvars[i], localvars[i]); // } //frames[meth.getInstructionLine(getStart())] = default_frame; } public Frame getDefaultFrame(){ return this.default_frame; } public MethodAnalyzer getMethodAnalyzer() { return analyzer; } private JvmType findArgument(int id) { for (int j = 0; j < refValues.length; j++) { if (refValues[j].isArgument() && (refValues[j].getId() == id)) { // id of static if(refValues[j] instanceof Reference && ((Reference)refValues[j]).getAll()!=null ){ return ((Reference)refValues[j]).getAll(); } return refValues[j]; } } System.err.println("Error: Interpreter.findArgument() found no such arg with id "+id); return null; } /* * gets a reference and returns its public or secret part * By default, it returns the public part.s */ private Reference getReferencePart(Reference r, FieldInstruction i) { if(i!=null) { int res = policy.findAttribute( i.getClassName(analyzer.getCpg()), i.getFieldName(analyzer.getCpg()) ); if(res == Policy.SECRET_ATTRIBUTE){ return r.hasSecret()?r.getSecret():r; } } if(r.hasPublic()) return r.getPublic(); return r; } public boolean hasSecret(String className){ return policy.findClass(className); } public static String getNameFromSignature(String sign){ String name = sign; if(sign.charAt(0)=='L'){ name = sign.substring(1, sign.indexOf(';')); } return name; } public InstructionHandle getCurrentInstruction() { return meth.getInstruction(line); } // Return Possible next instruction. // // - GOTO_INSTRUCTION: // * the target // // - IF1_INSTRUCTION: // - IF2_INSTRUCTION: // * the target // * the immediate following instruction // // - JSR_INSTRUCTION: // * the target // * the immediate following instruction (because RET will branch on it) // - RETURN_INSTRUCTION: // - VALUE_RETURN_INSTRUCTION: // - RET_INSTRUCTION: // - THROW_INSTRUCTION: // * no next instruction // // - ARITHMETIC1_INSTRUCTION: // - ARITHMETIC2_INSTRUCTION: // - ARRAY_LOAD_INSTRUCTION: // - ARRAY_STORE_INSTRUCTION: // - CAST_INSTRUCTION: // - COMPARISON_INSTRUCTION: // - CONSTANT_LOAD_INSTRUCTION: // - CONSTANT_PUSH_INSTRUCTION: // - CONVERSION_INSTRUCTION: // - DUP_INSTRUCTION: // - FIELD_STORE_INSTRUCTION: // - FIELD_LOAD_INSTRUCTION: // - INVOKE_INSTRUCTION: // - LOCAL_VARIABLE_STORE_INSTRUCTION: // - LOCAL_VARIABLE_LOAD_INSTRUCTION: // - MISC_INSTRUCTION: // - NEW_ARRAY_INSTRUCTION: // - NEW_INSTRUCTION: // - POP_INSTRUCTION: // - STATIC_INVOKE_INSTRUCTION: // - SWAP_INSTRUCTION: // - THROW_INSTRUCTION: // * the immediate following instruction // public ArrayList getNextInstructions(InstructionHandle ih, Frame fr) { ArrayList list = new ArrayList();; BranchInstruction branch; InstructionType type; Instruction inst = ih.getInstruction(); type = InstructionType.getType(inst); if (type == InstructionType.GOTO_INSTRUCTION) { branch = (BranchInstruction) (inst); list.add(branch.getTarget()); } else if (type == InstructionType.IF1_INSTRUCTION || type == InstructionType.IF2_INSTRUCTION) { branch = (BranchInstruction) (inst); list.add(branch.getTarget()); list.add(ih.getNext()); } else if (type == InstructionType.JSR_INSTRUCTION) { branch = (BranchInstruction) (inst); list.add(branch.getTarget()); } else if (type == InstructionType.RET_INSTRUCTION) { RET r = (RET)inst; MultiObject o = fr.getVariablesArray()[r.getIndex()]; JvmType[] pc = (JvmType[])o.content(); for(int i = 0; i < pc.length; i++) { Address a = (Address)pc[i]; list.add(meth.getInstruction(a.getPc())); } } else if (type == InstructionType.THROW_INSTRUCTION) { InstructionHandle[] except = meth.getRealExceptionHandlers(ih); for(int i = 0; i < except.length; i++) { list.add(except[i]); } } else if (type == InstructionType.SELECT_INSTRUCTION) { InstructionHandle targets[]; targets = ((Select) (inst)).getTargets(); list.add(((Select) inst).getTarget()); for (int i = targets.length; i > 0 ; i--) list.add(targets[i-1]); } else if (type == InstructionType.ARITHMETIC1_INSTRUCTION || type == InstructionType.ARITHMETIC2_INSTRUCTION || type == InstructionType.ARRAY_LOAD_INSTRUCTION || type == InstructionType.ARRAY_STORE_INSTRUCTION || type == InstructionType.CAST_INSTRUCTION || type == InstructionType.COMPARISON_INSTRUCTION || type == InstructionType.CONSTANT_LOAD_INSTRUCTION || type == InstructionType.CONSTANT_PUSH_INSTRUCTION || type == InstructionType.CONVERSION_INSTRUCTION || type == InstructionType.DUP_INSTRUCTION || type == InstructionType.FIELD_STORE_INSTRUCTION || type == InstructionType.FIELD_LOAD_INSTRUCTION || type == InstructionType.STATIC_FIELD_STORE_INSTRUCTION || type == InstructionType.STATIC_FIELD_LOAD_INSTRUCTION || type == InstructionType.INVOKE_INSTRUCTION || type == InstructionType.LOCAL_VARIABLE_STORE_INSTRUCTION || type == InstructionType.LOCAL_VARIABLE_LOAD_INSTRUCTION || type == InstructionType.MISC_INSTRUCTION || type == InstructionType.MONITOR_INSTRUCTION || type == InstructionType.NEW_ARRAY_INSTRUCTION || type == InstructionType.NEW_MULTI_ARRAY_INSTRUCTION || type == InstructionType.NEW_INSTRUCTION || type == InstructionType.POP_INSTRUCTION || type == InstructionType.POP2_INSTRUCTION || type == InstructionType.STATIC_INVOKE_INSTRUCTION || type == InstructionType.SWAP_INSTRUCTION || type == InstructionType.ARRAYLENGTH_INSTRUCTION) list.add(ih.getNext()); return list; } public ArrayList getNextExceptionHandlers(InstructionHandle ih) { ArrayList list = new ArrayList(); if(ih.getInstruction() instanceof ExceptionThrower || ih.getInstruction() instanceof ATHROW) { InstructionHandle ihs[] = meth.getRealExceptionHandlers(ih); for(int i = 0; i < ihs.length; i++) { list.add(ihs[i]); } } return list; } /** * abstract execution of an instruction * @param current the Instruction handler * @param fr the frame */ public void abstractExecutionStep(InstructionHandle current, Frame fr) { Instruction i; InstructionType itype; i = current.getInstruction(); itype = InstructionType.getType(i); line = meth.getInstructionLine(current); if (itype == InstructionType.ARITHMETIC1_INSTRUCTION) execArithmetic1((ArithmeticInstruction) i, fr); else if (itype == InstructionType.ARITHMETIC2_INSTRUCTION) execArithmetic2((ArithmeticInstruction) i, fr); else if (itype == InstructionType.ARRAY_LOAD_INSTRUCTION) execArrayLoad((ArrayInstruction) i, fr); else if (itype == InstructionType.ARRAY_STORE_INSTRUCTION) execArrayStore((ArrayInstruction) i, fr); else if (itype == InstructionType.CONSTANT_LOAD_INSTRUCTION) execConstantLoad((TypedInstruction) i, fr); else if (itype == InstructionType.CONSTANT_PUSH_INSTRUCTION) execConstantLoad((TypedInstruction) i, fr); else if (itype == InstructionType.CONVERSION_INSTRUCTION) execConversion((ConversionInstruction) i, fr); else if (itype == InstructionType.DUP_INSTRUCTION) execDup((StackInstruction) i, fr); else if (itype == InstructionType.FIELD_LOAD_INSTRUCTION) execGetField((FieldInstruction) i, fr); else if (itype == InstructionType.STATIC_FIELD_LOAD_INSTRUCTION) execGetStatic((FieldInstruction) i, fr); else if (itype == InstructionType.FIELD_STORE_INSTRUCTION) execPutField((FieldInstruction) i, fr); else if (itype == InstructionType.STATIC_FIELD_STORE_INSTRUCTION) execPutStatic((FieldInstruction) i, fr); else if (itype == InstructionType.IF1_INSTRUCTION) execIf1(fr); else if (itype == InstructionType.IF2_INSTRUCTION) execIf2(fr); else if (itype == InstructionType.INVOKE_INSTRUCTION) execInvoke((InvokeInstruction) i, fr); else if (itype == InstructionType.JSR_INSTRUCTION) execJsr(i, fr); else if (itype == InstructionType.LOCAL_VARIABLE_LOAD_INSTRUCTION) execVarLoad((LocalVariableInstruction) i, fr); else if (itype == InstructionType.LOCAL_VARIABLE_STORE_INSTRUCTION) execVarStore((LocalVariableInstruction) i, fr); else if (itype == InstructionType.MONITOR_INSTRUCTION) execPop(i, fr); else if (itype == InstructionType.NEW_ARRAY_INSTRUCTION) execNewArray(i, fr); else if (itype == InstructionType.NEW_MULTI_ARRAY_INSTRUCTION) execNewMultiArray((MULTIANEWARRAY) i, fr); else if (itype == InstructionType.NEW_INSTRUCTION) execNew((NEW) i, fr); else if (itype == InstructionType.POP_INSTRUCTION) execPop(i,fr); //fr.getStack().pop(); else if (itype == InstructionType.POP2_INSTRUCTION) execPop2(i,fr); else if (itype == InstructionType.SELECT_INSTRUCTION) fr.getStack().pop(); else if (itype == InstructionType.STATIC_INVOKE_INSTRUCTION) execInvoke((InvokeInstruction) i, fr); else if (itype == InstructionType.SWAP_INSTRUCTION) execSwap(i,fr); else if (itype == InstructionType.THROW_INSTRUCTION) { execThrow(i,fr); } else if (itype == InstructionType.CAST_INSTRUCTION) execCast(i, fr); else if (itype == InstructionType.COMPARISON_INSTRUCTION) execComp(i, fr); else if (itype == InstructionType.RETURN_INSTRUCTION){ // ReturnInstruction ri = (ReturnInstruction)i; //System.err.println(" ------------------ "+ri.getType(this.analyzer.getCpg()) + " "+ri.getType().getSignature()); } else if (itype == InstructionType.VALUE_RETURN_INSTRUCTION) ; else if (itype == InstructionType.RET_INSTRUCTION) ; else if (itype == InstructionType.GOTO_INSTRUCTION) ; else if (itype == InstructionType.ARRAYLENGTH_INSTRUCTION) execArrayLength(i,fr); else if (itype == InstructionType.MISC_INSTRUCTION) ; else { System.err.println("Interpreter.abstractExecutionStep(): Unhandled instruction " + i); } //return fr; } /* public Reference getArgument(int index) { return findArgument(i); for (int i = 0; i < refs.length; i++) { if (index == refs[i].getId() && refs[i].isArgument()) { return refs[i]; } } System.err.println("Error: Interpreter.getArgument() found no matching reference"); return null; } */ /* public Reference getRef(int line) { for (int i = 0; i < refs.length; i++) { if (line == refs[i].getId() && !refs[i].isArgument()) { return refs[i]; } } System.err.println("Error: Interpreter.getRef() found no matching reference"); return null; } */ public JvmType getRefValue(int line) { for(int i = 0; i < refValues.length; i++) { if(line == refValues[i].getId() && !refValues[i].isArgument()) { if(refValues[i] instanceof Reference && ((Reference)refValues[i]).getAll()!=null) return ((Reference)refValues[i]).getAll(); return refValues[i]; } } System.err.println("Error: Interpreter.getRefValue() found no matching referenceValue for line = "+line); return null; } public Reference getConstantRef() { return constant_ref; } public Reference getNullRef() { return null_ref; } public Reference getExceptionRef() { return exception_ref; } public Reference[] getRefs() { return refs; } public Value[] getValues() { return values; } public JvmType[] getRefValues() { return refValues; } public int getRefValuesLength() { return refValuesLength; } public Address getAddress(int line) { for (int i = 0; i < addresses.length; i++) { if (line == addresses[i].getPc()) { return addresses[i]; } } System.err .println("Error: Interpreter.getAddress() found no matching address"); return addresses[0]; } public Address[] getAddresses() { return addresses; } /* * searches in [References, Values, Adresses] */ public int getJvmTypeIndex(JvmType j) { if(j instanceof Reference) j = ((Reference)j).getAll(); for(int i = 0; i < refValues.length; i++) if(refValues[i] == j) return i; for(int i = 0; i < addresses.length; i++) if(addresses[i] == j) return i+refValues.length; return -1; } public InstructionHandle getStart() { return meth.firstInstruction(); } /* public Frame getFrame(InstructionHandle ih) { return frames[meth.getInstructionLine(ih)]; } public boolean recordFrame(InstructionHandle ih, Frame fr) { boolean updated = true; if(frames[meth.getInstructionLine(ih)] == null) { frames[meth.getInstructionLine(ih)] = (Frame)fr.clone(); } else { updated = frames[meth.getInstructionLine(ih)].merge(fr); } return updated; } */ public MethodInfo getMethodInfo() { return meth; } public int getInstructionLine(InstructionHandle ih) { return meth.getInstructionLine(ih); } // abstract execution of arithmetic instructions which take one argument on // the stack private void execArithmetic1(ArithmeticInstruction i, Frame f) { //TODO this affects the argument on the stack? } // abstract execution of arithmetic instructions which take two arguments on // the stack and push the results private void execArithmetic2(ArithmeticInstruction i, Frame f) { //TODO - do arguments leak? MultiObject res = new MultiObject(); ExecutionStack stack = f.getStack(); switch(i.getOpcode()){ case Constants.DADD : case Constants.DDIV : case Constants.DMUL : case Constants.DREM : case Constants.DSUB : case Constants.LADD : case Constants.LAND : case Constants.LDIV : case Constants.LMUL : case Constants.LOR : case Constants.LREM : case Constants.LSUB : case Constants.LXOR : res.merge(stack.pop()); stack.pop(); res.merge(stack.pop()); stack.pop(); stack.push(res); stack.push(res); break; case Constants.LSHL : case Constants.LSHR : case Constants.LUSHR : res.merge(stack.pop()); stack.pop(); res.merge(stack.pop()); stack.push(res); stack.push(res); break; default: res.merge(stack.pop()); res.merge(stack.pop()); stack.push(res); } } // abstract execution of a load from an array // the result on the abstract stack is the union of set of values contained // in the set of array references popped on the abstract stack private void execArrayLoad(ArrayInstruction i, Frame f) { MultiObject arrayref; ExecutionStack stack = f.getStack(); stack.pop(); arrayref = stack.pop(); stack.push(arrayref); switch(i.getOpcode()){ case Constants.LALOAD: case Constants.DALOAD: stack.push(arrayref); break; default: } } // abstract execution of a store in an array private void execArrayStore(ArrayInstruction i, Frame f) { MultiObject arrayref, value; ExecutionStack stack = f.getStack(); switch(i.getOpcode()){ case Constants.LASTORE: case Constants.DASTORE: stack.pop(); break; default: } value = stack.pop(); stack.pop(); // index arrayref = stack.pop(); f.new_makePoint(arrayref, value, i.getType(this.analyzer.getCpg())); } /** * abstract execution of a constand load * @param i * @param f */ private void execConstantLoad(TypedInstruction i, Frame f) { MultiObject constant; Type t; String sign; constant = new MultiObject(); t = i.getType(analyzer.getCpg()); sign = t.getSignature(); if (i instanceof ACONST_NULL) { constant.add(getNullRef()); } else if (sign.charAt(0) == '[' || sign.charAt(0) == 'L') { constant.add(getConstantRef()); } else if (t.getSize() == 1) { constant.add(Value.getShortInstance()); } else{ //if size == 2 constant.add(Value.getLongInstance()); f.getStack().push(constant); } f.getStack().push(constant); } // abstact execution of conversion bytecode like i2d private void execConversion(ConversionInstruction i, Frame f){ ExecutionStack stack = f.getStack(); switch(i.getOpcode()){ case Constants.D2F : case Constants.D2I : case Constants.L2F : case Constants.L2I : stack.pop(); break; case Constants.I2D : case Constants.I2L : case Constants.F2D : case Constants.F2L : MultiObject res = stack.pop(); stack.push(res); stack.push(res); break; default: } } /** * abstract execution of a getfield bytcode * the result on the abstract stack is the union of the set of values * contained by each object reference in the the set of reference on the * abstract stack * @param i * @param f */ private void execGetField(FieldInstruction i, Frame f) { MultiObject objectref; ExecutionStack stack = f.getStack(); objectref = stack.pop(); Type t = i.getFieldType(analyzer.getCpg()); JvmType[] content = objectref.content(); MultiObject res = new MultiObject(); for(int j = 0; j < content.length; j++) { if(content[j] instanceof Reference) { Reference r = (Reference)content[j]; if(r.isWholePart()) { res.add(getReferencePart(r, i)); } else{ if(r.isPublicPart()){ res.add(getReferencePart(r.getAll(), i)); } else res.add(r); } } else { System.err.println("GETFIELD: reference expected but not founded!"); } } /* content = res.content(); int linkType = MethodInfo.linkType(t); for(int j = 0; j < content.length; j++){ res.merge(f.pointedBy(content[j], linkType, content[j].getPartType(), JvmType.WHOLE_PART)); } */ stack.push(res); if(t.getSize() == 2) stack.push(res); //keep external fields this.analyzer.addExternalField(i); } /** * abstract execution of a putfield bytecode * @param i * @param f */ private void execPutField(FieldInstruction i, Frame f) { MultiObject objectref, value; ExecutionStack stack = f.getStack(); Type t = i.getType(analyzer.getCpg()); value = stack.pop(); if(t.getSize()==2){ stack.pop(); } objectref = stack.pop(); JvmType[] content = objectref.content(); MultiObject res = new MultiObject(); for(int j = 0; j < content.length; j++) { if(content[j] instanceof Reference) { Reference r = (Reference)content[j]; if(r.isWholePart()) { res.add(getReferencePart(r, i)); } else if(r.isPublicPart()){ res.add(getReferencePart(r.getAll(), i)); } else res.add(r); } else { System.err.println("PUTFIELD: reference expected but not found!"); } } f.new_makePoint(res, value, t); //keep external fields this.analyzer.addExternalField(i); } /** * * @param f */ private void execIf1(Frame f) { f.getStack().pop(); } /** * * @param f */ private void execIf2(Frame f) { f.getStack().pop(); f.getStack().pop(); } /** * * @param i * @param f */ private void execJsr(Instruction i, Frame f) { MultiObject res = new MultiObject(); res.add(getAddress(line)); f.getStack().push(res); } /** * abstract execution of an invoke bytecode * the abstract execution of a method invokation consists in: * - collecting arguments * - if the method returns a value, creation of the value returned * - find the signature * - updating the arguments according to the signature * @param i * @param f */ private void execInvoke(InvokeInstruction i, Frame f) { int argc; MultiObject argv[], returnObject = null; Type t; argc = i.getArgumentTypes(analyzer.getCpg()).length; int realArgc = argc; if(! (i instanceof INVOKESTATIC)) realArgc++; Type [] argvType; argvType = i.getArgumentTypes(analyzer.getCpg()); argv = new MultiObject[realArgc]; while (argc > 0) { argv[realArgc-1] = f.getStack().pop(); if(argvType[argc-1].getSize() == 2){ f.getStack().pop(); } argc--; realArgc--; } if(!(i instanceof INVOKESTATIC)) { argv[0] = f.getStack().pop(); if(i.getClassType(analyzer.getCpg()).getSize() == 2){ f.getStack().pop(); } } t = i.getReturnType(analyzer.getCpg()); returnObject = new MultiObject(); if (!t.equals(Type.VOID)) { JvmType returnValue = getRefValue(line); if(returnValue != null) returnObject.add(returnValue); } String key = SignatureDictionary.key(i,analyzer.getCpg()); boolean exact = (i instanceof INVOKESTATIC) || (i instanceof INVOKESPECIAL) || argv[0].hasExactType(); int signType = exact ? SignatureDictionary.EXACT_SIGN_IDX : SignatureDictionary.GLOBAL_SIGN_IDX; //FIXME not take into consideration if internal method this.analyzer.addExternalMethod(i, signType); if(Config.statisticsEnabled()) { if(exact) Stats.noExactInvoke++; else Stats.noGlobalInvoke++; } Signature signature = analyzer.getDictionary().findSignature(key,exact); if(signature != null) this.isFinal = this.isFinal && signature.isFinal(); else this.isFinal = false; if (signature != null && (!key.startsWith("java.lang.System.arraycopy") || !(isPrimitiveArray(argv[0].getExactType()) || isPrimitiveArray(argv[2].getExactType())))) { f.new_applySignature(signature, returnObject, argv); } else{ Printer.debugPrintln("Warning: Signature for method " + key + " cannot be found"); Printer.debugPrintln("Warning: Signature for method " + key + " needed in method "+this.meth.getClassName()+"."+ this.meth.getMethod().getName()); } if (!t.equals(Type.VOID)) { f.getStack().push(returnObject); if(t.getSize() == 2){ f.getStack().push(returnObject); } } } /** * * @param t * @return */ private boolean isPrimitiveArray(Type t) { return t != null && (t instanceof ArrayType) && ((ArrayType)t).getBasicType() instanceof BasicType; } /** * * @param i * @param f */ private void execCast(Instruction i, Frame f) { MultiObject res = new MultiObject(); ExecutionStack stack = f.getStack(); if (i instanceof INSTANCEOF) { stack.pop(); res.add(Value.getShortInstance()); stack.push(res); } } /** * * @param i * @param f */ private void execComp(Instruction i, Frame f) { MultiObject res = new MultiObject(); ExecutionStack stack = f.getStack(); switch(i.getOpcode()){ case Constants.DCMPG: case Constants.DCMPL: case Constants.LCMP: stack.pop(); // value1 stack.pop(); // value2 break; default: } stack.pop(); // value1 stack.pop(); // value2 res.add(Value.getShortInstance()); stack.push(res); } /** * Combines the local variable array abstraction at line 'previous' with the * one at line 'current' * @param i * @param f */ private void execDup(StackInstruction i, Frame f) { ExecutionStack stack = f.getStack(); MultiObject val1, val2, val3, val4; switch (i.getOpcode()) { case Constants.DUP: val1 = stack.peek(); stack.push((MultiObject) val1.clone()); break; case Constants.DUP_X1: val1 = stack.pop(); val2 = stack.pop(); stack.push((MultiObject) val1.clone()); stack.push(val2); stack.push(val1); break; case Constants.DUP_X2: val1 = stack.pop(); val2 = stack.pop(); /*if (val1.typeSize() == 2) { stack.push((MultiObject) val1.clone()); stack.push(val2); stack.push(val1); } else {*/ val3 = stack.pop(); stack.push((MultiObject) val1.clone()); stack.push(val3); stack.push(val2); stack.push(val1); //} break; case Constants.DUP2: val1 = stack.pop(); /*if (val1.typeSize() == 2) { stack.push(val1); stack.push((MultiObject) val1.clone()); } else {*/ val2 = stack.pop(); stack.push(val2); stack.push(val1); stack.push((MultiObject) val2.clone()); stack.push((MultiObject) val1.clone()); //} break; case Constants.DUP2_X1: val1 = stack.pop(); /*if (val1.typeSize() == 2) { val2 = stack.pop(); stack.push((MultiObject) val1.clone()); stack.push(val2); stack.push(val1); } else {*/ val2 = stack.pop(); val3 = stack.pop(); stack.push((MultiObject) val2.clone()); stack.push((MultiObject) val1.clone()); stack.push(val3); stack.push(val2); stack.push(val1); //} break; case Constants.DUP2_X2: val1 = stack.pop(); val2 = stack.pop(); val3 = stack.pop(); val4 = stack.pop(); stack.push((MultiObject) val1.clone()); stack.push((MultiObject) val2.clone()); stack.push(val4); stack.push(val3); stack.push(val2); stack.push(val1); /* if (val1.typeSize() == 2) { if (val2.typeSize() == 2) { stack.push((MultiObject) val1.clone()); stack.push(val2); stack.push(val1); } val3 = stack.pop(); stack.push((MultiObject) val2.clone()); stack.push((MultiObject) val1.clone()); stack.push(val3); stack.push(val2); stack.push(val1); } else { val3 = stack.pop(); if (val3.typeSize() == 2) { stack.push((MultiObject) val2.clone()); stack.push((MultiObject) val1.clone()); stack.push(val3); stack.push(val2); stack.push(val1); } else { val4 = stack.pop(); stack.push((MultiObject) val1.clone()); stack.push((MultiObject) val2.clone()); stack.push(val4); stack.push(val3); stack.push(val2); stack.push(val1); } } */ break; default: break; } } /** * abstract execution of a local variable load * @param i * @param f */ private void execVarLoad(LocalVariableInstruction i, Frame f) { f.getStack().push(f.getVariablesArray()[i.getIndex()]); switch(i.getOpcode()){ case Constants.DLOAD : case Constants.DLOAD_0 : case Constants.DLOAD_1 : case Constants.DLOAD_2 : case Constants.DLOAD_3 : case Constants.LLOAD : case Constants.LLOAD_0 : case Constants.LLOAD_1 : case Constants.LLOAD_2 : case Constants.LLOAD_3 : f.getStack().push(f.getVariablesArray()[i.getIndex()+1]); break; default: } } /** * abstract execution of a local variale store * @param i * @param f */ private void execVarStore(LocalVariableInstruction i, Frame f) { f.getVariablesArray()[i.getIndex()] = f.getStack().pop(); switch(i.getOpcode()){ case Constants.DSTORE : case Constants.DSTORE_0 : case Constants.DSTORE_1 : case Constants.DSTORE_2 : case Constants.DSTORE_3 : case Constants.LSTORE : case Constants.LSTORE_0 : case Constants.LSTORE_1 : case Constants.LSTORE_2 : case Constants.LSTORE_3 : f.getVariablesArray()[i.getIndex()+1] = f.getStack().pop(); break; default: } } /** * abstract execution of POP * @param i * @param f */ private void execPop(Instruction i, Frame f) { f.getStack().pop(); } /** * abstract execution of POP2 * @param i * @param f */ private void execPop2(Instruction i, Frame f) { f.getStack().pop(); f.getStack().pop(); } /** * * @param i * @param f */ private void execArrayLength(Instruction i, Frame f) { } /** * abstract execution of an array creation * @param i * @param f */ private void execNewArray(Instruction i, Frame f) { ExecutionStack stack = f.getStack(); MultiObject arrayref = new MultiObject(); stack.pop(); // count arrayref.add(getRefValue(line)); stack.push(arrayref); } /** * abstract execution of a multi array creation * @param i * @param f */ private void execNewMultiArray(MULTIANEWARRAY i, Frame f) { MultiObject arrayref = new MultiObject(); ExecutionStack stack = f.getStack(); int dims = i.getDimensions(); for (int n = 1; n <= dims; n++) stack.pop(); arrayref.add(getRefValue(line)); stack.push(arrayref); } /** * abstract execution of an object creation * @param i * @param f */ private void execNew(NEW i, Frame f) { MultiObject res = new MultiObject(); res.add(getRefValue(line)); f.getStack().push(res); } /** * abstract execution of a swap * @param i * @param f */ private void execSwap(Instruction i, Frame f) { MultiObject value1, value2; ExecutionStack stack = f.getStack(); value1 = stack.pop(); value2 = stack.pop(); stack.push(value1); stack.push(value2); } /** * * @param i * @param f */ private void execGetStatic(FieldInstruction i, Frame f) { ExecutionStack stack = f.getStack(); Type t = i.getFieldType(analyzer.getCpg()); if (t instanceof ReferenceType) { stack.push(f.getStaticWorld()); } else { MultiObject res = f.getStaticWorld(); if(t.getSize() == 2){ stack.push(res); stack.push(res); } else{ stack.push(res); } } } /** * abstract execution of PUTSTATIC bytecode * @param i * @param f */ private void execPutStatic(FieldInstruction i, Frame f) { MultiObject value; ExecutionStack stack = f.getStack(); value = stack.pop(); Type t = i.getType(analyzer.getCpg()); if(t.getSize() == 2){ stack.pop(); } //FIXME //f.makePoint(f.getStaticWorld(), value, t); f.new_simpleMakePoint(f.getStaticWorld(), value, t); f.new_makePointedBy(f.getStaticWorld(), value); } private void execThrow(Instruction i, Frame f) { MultiObject value = f.getStack().pop(); f.getStack().clear(); f.getStack().push(value); f.new_simpleMakePoint(f.getException(), value, Type.OBJECT); f.new_makePointedBy(f.getException(), value); //f.makePoint(f.getException(), value, Type.OBJECT); /* f.simpleMakePoint(f.getException(), value, Type.OBJECT); f.makePointTo(f.getException(), value); */ } /** * * A signature is final if the methods does not invoke other methods, or if all * the invoked methods are final. * During the iterized analysis, on a set of classes, only methods having not final signatures will * be reanalyzed. * @return true if the signature is final or false otherwise */ public boolean isFinalSignature(){ return this.isFinal; } public int getLine() { return this.line; } }