/** * Find the declared exceptions for the method called by given instruction. * * @param inv * the InvokeInstruction * @param cpg * the ConstantPoolGen used by the class the InvokeInstruction * belongs to * @return array of ObjectTypes of thrown exceptions, or null if we can't * find the method implementation */ public static @CheckForNull ObjectType[] findDeclaredExceptions(InvokeInstruction inv, ConstantPoolGen cpg) { XMethod method = findInvocationLeastUpperBound(inv, cpg, inv instanceof INVOKESTATIC ? Hierarchy.STATIC_METHOD : Hierarchy.INSTANCE_METHOD); if (method == null) return null; String[] exceptions = method.getThrownExceptions(); if (exceptions == null) return new ObjectType[0]; ObjectType[] result = new ObjectType[exceptions.length]; for (int i = 0; i < exceptions.length; ++i) { result[i] = ObjectTypeFactory.getInstance(ClassName.toDottedClassName(exceptions[i])); } return result; }
/** * Get the inner class access object for given invokestatic instruction. * Returns null if the called method is not an inner class access. * * @param inv the invokestatic instruction * @param cpg the ConstantPoolGen for the method * @return the InnerClassAccess, or null if the call is not an inner class access */ public InnerClassAccess getInnerClassAccess(INVOKESTATIC inv, ConstantPoolGen cpg) throws ClassNotFoundException { String methodName = inv.getMethodName(cpg); if (methodName.startsWith("access$")) { String className = inv.getClassName(cpg); return getInnerClassAccess(className, methodName); } return null; }
/** * Translate code to call the BasisLibrary.unallowed_extensionF(String) * method. */ private void translateUnallowedExtension(ConstantPoolGen cpg, InstructionList il) { int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "unallowed_extension_functionF", "(Ljava/lang/String;)V"); il.append(new PUSH(cpg, _fname.toString())); il.append(new INVOKESTATIC(index)); }
/** * Is the given instruction a self-call? */ private Method isSelfCall(InvokeInstruction inv) { ConstantPoolGen cpg = classContext.getConstantPoolGen(); JavaClass jclass = classContext.getJavaClass(); String calledClassName = inv.getClassName(cpg); // FIXME: is it possible we would see a superclass name here? // Not a big deal for now, as we are mostly just interested in calls // to private methods, for which we will definitely see the right // called class name. if (!calledClassName.equals(jclass.getClassName())) return null; String calledMethodName = inv.getMethodName(cpg); String calledMethodSignature = inv.getSignature(cpg); boolean isStaticCall = (inv instanceof INVOKESTATIC); // Scan methods for one that matches. Method[] methods = jclass.getMethods(); for (Method method : methods) { String methodName = method.getName(); String signature = method.getSignature(); boolean isStatic = method.isStatic(); if (methodName.equals(calledMethodName) && signature.equals(calledMethodSignature) && isStatic == isStaticCall) { // This method looks like a match. return wantCallsFor(method) ? method : null; } } // Hmm...no matching method found. // This is almost certainly because the named method // was inherited from a superclass. if (DEBUG) System.out.println("No method found for " + calledClassName + "." + calledMethodName + " : " + calledMethodSignature); return null; }
/** * Use this to screen out methods that do not contain invocations. */ public boolean prescreen(ClassContext classContext, Method method) { BitSet bytecodeSet = classContext.getBytecodeSet(method); return bytecodeSet != null && (bytecodeSet.get(Constants.INVOKEINTERFACE) || bytecodeSet.get(Constants.INVOKEVIRTUAL) || bytecodeSet.get(Constants.INVOKESPECIAL) || bytecodeSet.get(Constants.INVOKESTATIC) || bytecodeSet .get(Constants.INVOKENONVIRTUAL)); }
@Override public void visitINVOKESTATIC(INVOKESTATIC obj) { if (returnsString(obj)) { consumeStack(obj); String className = obj.getClassName(getCPG()); if (className.equals("java.lang.String")) { pushValue(dynamicStringTypeInstance); } else { pushReturnType(obj); } } else { super.visitINVOKESTATIC(obj); } }
private void inspectLocation(JavaClass jclass, ConstantPoolGen cpg, Method method, MethodGen methodGen, LinkedList<WarningWithProperties> refComparisonList, LinkedList<WarningWithProperties> stringComparisonList, RefComparisonTypeFrameModelingVisitor visitor, TypeDataflow typeDataflow, Location location) throws DataflowAnalysisException { Instruction ins = location.getHandle().getInstruction(); short opcode = ins.getOpcode(); if (opcode == Constants.IF_ACMPEQ || opcode == Constants.IF_ACMPNE) { checkRefComparison(location, jclass, method, methodGen, visitor, typeDataflow, stringComparisonList, refComparisonList); } else if (ins instanceof InvokeInstruction) { InvokeInstruction inv = (InvokeInstruction) ins; boolean isStatic = inv instanceof INVOKESTATIC; @DottedClassName String className = inv.getClassName(cpg); String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); if ( methodName.equals("assertSame") && methodSig.equals("(Ljava/lang/Object;Ljava/lang/Object;)V")) { checkRefComparison(location, jclass, method, methodGen, visitor, typeDataflow, stringComparisonList, refComparisonList); } boolean equalsMethod = !isStatic && methodName.equals("equals") && methodSig.equals("(Ljava/lang/Object;)Z") || isStatic && methodName.equals("assertEquals") && methodSig.equals("(Ljava/lang/Object;Ljava/lang/Object;)V") && !className.equals("org.testng.Assert") || isStatic && methodName.equals("equal") && methodSig.equals("(Ljava/lang/Object;Ljava/lang/Object;)Z") && className.equals("com.google.common.base.Objects"); if (equalsMethod) { checkEqualsComparison(location, jclass, method, methodGen, cpg, typeDataflow); } } }
/** * @param cpg * @param inv * @return */ public MethodDescriptor getInvokedMethod(ConstantPoolGen cpg, InvokeInstruction inv) { String invoked = inv.getClassName(cpg); String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); MethodDescriptor invokedMethod = DescriptorFactory.instance().getMethodDescriptor(ClassName.toSlashedClassName(invoked), methodName, methodSig, inv instanceof INVOKESTATIC); return invokedMethod; }
private boolean prescreen(ClassContext classContext, Method method) { BitSet bytecodeSet = classContext.getBytecodeSet(method); if (bytecodeSet == null) return false; // method must acquire a lock if (!bytecodeSet.get(Constants.MONITORENTER) && !method.isSynchronized()) return false; // and contain a static method invocation if (!bytecodeSet.get(Constants.INVOKESTATIC)) return false; return true; }
private void analyzeMethod(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { // System.out.println("Checking " + method); CFG cfg = classContext.getCFG(method); LockDataflow lockDataflow = classContext.getLockDataflow(method); for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { Location location = i.next(); Instruction ins = location.getHandle().getInstruction(); if (!(ins instanceof INVOKESTATIC)) continue; if (!isSleep((INVOKESTATIC) ins, classContext.getConstantPoolGen())) continue; // System.out.println("Found sleep at " + location.getHandle()); LockSet lockSet = lockDataflow.getFactAtLocation(location); if (lockSet.getNumLockedObjects() > 0) { bugAccumulator.accumulateBug( new BugInstance(this, "SWL_SLEEP_WITH_LOCK_HELD", NORMAL_PRIORITY).addClassAndMethod( classContext.getJavaClass(), method), classContext, method, location); } } bugAccumulator.reportAccumulatedBugs(); }
private boolean isSleep(INVOKESTATIC ins, ConstantPoolGen cpg) { String className = ins.getClassName(cpg); if (!className.equals("java.lang.Thread")) return false; String methodName = ins.getMethodName(cpg); String signature = ins.getSignature(cpg); return methodName.equals("sleep") && (signature.equals("(J)V") || signature.equals("(JI)V")); }
@Override public void visitINVOKESTATIC(INVOKESTATIC ins) { // Find calls to System.exit(), since this effectively terminates the // basic block. String className = ins.getClassName(constPoolGen); String methodName = ins.getName(constPoolGen); String methodSig = ins.getSignature(constPoolGen); if (className.equals("java.lang.System") && methodName.equals("exit") && methodSig.equals("(I)V")) isExit = true; }
/** * Determine if given Instruction is a monitor wait. * * @param ins * the Instruction * @param cpg * the ConstantPoolGen for the Instruction * * @return true if the instruction is a monitor wait, false if not */ public static boolean isMonitorWait(Instruction ins, ConstantPoolGen cpg) { if (!(ins instanceof InvokeInstruction)) return false; if (ins.getOpcode() == Constants.INVOKESTATIC) return false; InvokeInstruction inv = (InvokeInstruction) ins; String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); return isMonitorWait(methodName, methodSig); }
/** * Determine if given Instruction is a monitor wait. * * @param ins * the Instruction * @param cpg * the ConstantPoolGen for the Instruction * * @return true if the instruction is a monitor wait, false if not */ public static boolean isMonitorNotify(Instruction ins, ConstantPoolGen cpg) { if (!(ins instanceof InvokeInstruction)) return false; if (ins.getOpcode() == Constants.INVOKESTATIC) return false; InvokeInstruction inv = (InvokeInstruction) ins; String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); return isMonitorNotify(methodName, methodSig); }
/** * Get the InnerClassAccess for access method called by given INVOKESTATIC. * * @param inv * the INVOKESTATIC instruction * @param cpg * the ConstantPoolGen for the method * @return the InnerClassAccess, or null if the instruction is not an * inner-class access */ public static InnerClassAccess getInnerClassAccess(INVOKESTATIC inv, ConstantPoolGen cpg) throws ClassNotFoundException { String className = inv.getClassName(cpg); String methodName = inv.getName(cpg); String methodSig = inv.getSignature(cpg); InnerClassAccess access = AnalysisContext.currentAnalysisContext().getInnerClassAccessMap() .getInnerClassAccess(className, methodName); return (access != null && access.getMethodSignature().equals(methodSig)) ? access : null; }
/** Checks if the constraints of operands of the said instruction(s) are satisfied. */ public void visitINVOKESTATIC(INVOKESTATIC o){ try { // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in, // is therefore resolved/verified. // INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified, // too. So are the allowed method names. String classname = o.getClassName(cpg); JavaClass jc = Repository.lookupClass(classname); Method[] ms = jc.getMethods(); Method m = null; for (int i=0; i<ms.length; i++){ if ( (ms[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ m = ms[i]; break; } } if (m == null){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg) +"' not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); } else if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2. constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset."); } } catch (ClassNotFoundException e) { // FIXME: maybe not the best way to handle this throw new AssertionViolatedException("Missing class: " + e.toString()); } }
/** @see org.apache.bcel.generic.Visitor */ public void visitINVOKESTATIC(INVOKESTATIC aINVOKESTATIC) { addInvokeReference( new InvokeReference(aINVOKESTATIC, mCurrentPoolGen)); }
@Override public void visitINVOKESTATIC(INVOKESTATIC obj) { visitInvoke(obj); }
private boolean instructionisPause(InstructionHandle ih) { ConstantPoolGen cp = methodGen.getConstantPool(); int indexPauseInstruction = cp.lookupMethodref("ibis.cashmere.CashmereObject", "pause", "()V"); if (indexPauseInstruction < 0) return false; return ih.getInstruction().equals(new INVOKESTATIC(indexPauseInstruction)); }
public void visitINVOKESTATIC(INVOKESTATIC s) { String t = s.getClassName(poolGen); log.log(" instr(invokestatic)=" + t, Project.MSG_DEBUG); design.checkClass(t); }
private void checkRefComparison(Location location, JavaClass jclass, Method method, MethodGen methodGen, RefComparisonTypeFrameModelingVisitor visitor, TypeDataflow typeDataflow, List<WarningWithProperties> stringComparisonList, List<WarningWithProperties> refComparisonList) throws DataflowAnalysisException { InstructionHandle handle = location.getHandle(); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (frame.getStackDepth() < 2) { throw new DataflowAnalysisException("Stack underflow", methodGen, handle); } int numSlots = frame.getNumSlots(); Type lhsType = frame.getValue(numSlots - 2); Type rhsType = frame.getValue(numSlots - 1); if (lhsType instanceof NullType || rhsType instanceof NullType) { return; } if (lhsType instanceof ReferenceType && rhsType instanceof ReferenceType) { IncompatibleTypes result = IncompatibleTypes.getPriorityForAssumingCompatible(lhsType, rhsType, true); if (result != IncompatibleTypes.SEEMS_OK && result != IncompatibleTypes.UNCHECKED) { String sourceFile = jclass.getSourceFileName(); boolean isAssertSame = handle.getInstruction() instanceof INVOKESTATIC; if (isAssertSame) bugAccumulator.accumulateBug( new BugInstance(this, "TESTING", result.getPriority()) .addClassAndMethod(methodGen, sourceFile) .addString("Calling assertSame with two distinct objects") .addFoundAndExpectedType(rhsType, lhsType) .addSomeSourceForTopTwoStackValues(classContext, method, location), SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, sourceFile, handle)); else bugAccumulator.accumulateBug( new BugInstance(this, "EC_UNRELATED_TYPES_USING_POINTER_EQUALITY", result.getPriority()) .addClassAndMethod(methodGen, sourceFile).addFoundAndExpectedType(rhsType, lhsType) .addSomeSourceForTopTwoStackValues(classContext, method, location), SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, sourceFile, handle)); return; } if (lhsType.equals(Type.OBJECT) && rhsType.equals(Type.OBJECT)) return; String lhs = SignatureConverter.convert(lhsType.getSignature()); String rhs = SignatureConverter.convert(rhsType.getSignature()); if (lhs.equals("java.lang.String") || rhs.equals("java.lang.String")) { handleStringComparison(jclass, method, methodGen, visitor, stringComparisonList, location, lhsType, rhsType); } else if (suspiciousSet.contains(lhs)) { handleSuspiciousRefComparison(jclass, method, methodGen, refComparisonList, location, lhs, (ReferenceType) lhsType, (ReferenceType) rhsType); } else if (suspiciousSet.contains(rhs)) { handleSuspiciousRefComparison(jclass, method, methodGen, refComparisonList, location, rhs, (ReferenceType) lhsType, (ReferenceType) rhsType); } } }
/** * Determine whether or not the the given method is a getter method. I.e., * if it just returns the value of an instance field. * * @param classContext * the ClassContext for the class containing the method * @param method * the method */ @SuppressWarnings("unchecked") public static boolean isGetterMethod(ClassContext classContext, Method method) { MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) return false; InstructionList il = methodGen.getInstructionList(); // System.out.println("Checking getter method: " + method.getName()); if (il.getLength() > 60) return false; int count = 0; Iterator<InstructionHandle> it = il.iterator(); while (it.hasNext()) { InstructionHandle ih = it.next(); switch (ih.getInstruction().getOpcode()) { case Constants.GETFIELD: count++; if (count > 1) return false; break; case Constants.PUTFIELD: case Constants.BALOAD: case Constants.CALOAD: case Constants.DALOAD: case Constants.FALOAD: case Constants.IALOAD: case Constants.LALOAD: case Constants.SALOAD: case Constants.AALOAD: case Constants.BASTORE: case Constants.CASTORE: case Constants.DASTORE: case Constants.FASTORE: case Constants.IASTORE: case Constants.LASTORE: case Constants.SASTORE: case Constants.AASTORE: case Constants.PUTSTATIC: return false; case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: case Constants.INVOKEINTERFACE: case Constants.INVOKESPECIAL: case Constants.GETSTATIC: // no-op } } // System.out.println("Found getter method: " + method.getName()); return true; }
@Override public void visitINVOKESTATIC(INVOKESTATIC inv) { handleInvoke(inv); }
public static @CheckForNull JavaClassAndMethod findInvocationLeastUpperBound(InvokeInstruction inv, ConstantPoolGen cpg, JavaClassAndMethodChooser methodChooser) throws ClassNotFoundException { if (DEBUG_METHOD_LOOKUP) { System.out.println("Find prototype method for " + SignatureConverter.convertMethodSignature(inv, cpg)); } short opcode = inv.getOpcode(); if (opcode == Constants.INVOKESTATIC) { if (methodChooser == INSTANCE_METHOD) return null; } else { if (methodChooser == STATIC_METHOD) return null; } // Find the method if (opcode == Constants.INVOKESPECIAL) { // Non-virtual dispatch return findExactMethod(inv, cpg, methodChooser); } else { String className = inv.getClassName(cpg); String methodName = inv.getName(cpg); String methodSig = inv.getSignature(cpg); if (DEBUG_METHOD_LOOKUP) { System.out.println("[Class name is " + className + "]"); System.out.println("[Method name is " + methodName + "]"); System.out.println("[Method signature is " + methodSig + "]"); } if (className.startsWith("[")) { // Java 1.5 allows array classes to appear as the class name className = "java.lang.Object"; } JavaClass jClass = Repository.lookupClass(className); return findInvocationLeastUpperBound(jClass, methodName, methodSig, methodChooser, opcode == Constants.INVOKEINTERFACE); } }
/** * Resolve possible method call targets. This works for both static and * instance method calls. * * @param invokeInstruction * the InvokeInstruction * @param typeFrame * the TypeFrame containing the types of stack values * @param cpg * the ConstantPoolGen * @return Set of methods which might be called * @throws DataflowAnalysisException * @throws ClassNotFoundException */ public static Set<JavaClassAndMethod> resolveMethodCallTargets(InvokeInstruction invokeInstruction, TypeFrame typeFrame, ConstantPoolGen cpg) throws DataflowAnalysisException, ClassNotFoundException { short opcode = invokeInstruction.getOpcode(); if (opcode == Constants.INVOKESTATIC) { HashSet<JavaClassAndMethod> result = new HashSet<JavaClassAndMethod>(); JavaClassAndMethod targetMethod = findInvocationLeastUpperBound(invokeInstruction, cpg, CONCRETE_METHOD); if (targetMethod != null) { result.add(targetMethod); } return result; } if (!typeFrame.isValid()) { return new HashSet<JavaClassAndMethod>(); } Type receiverType; boolean receiverTypeIsExact; if (opcode == Constants.INVOKESPECIAL) { // invokespecial instructions are dispatched to EXACTLY // the class specified by the instruction receiverType = ObjectTypeFactory.getInstance(invokeInstruction.getClassName(cpg)); receiverTypeIsExact = false; // Doesn't actually matter } else { // For invokevirtual and invokeinterface instructions, we have // virtual dispatch. By taking the receiver type (which may be a // subtype of the class specified by the instruction), // we may get a more precise set of call targets. int instanceStackLocation = typeFrame.getInstanceStackLocation(invokeInstruction, cpg); receiverType = typeFrame.getStackValue(instanceStackLocation); if (!(receiverType instanceof ReferenceType)) { return new HashSet<JavaClassAndMethod>(); } receiverTypeIsExact = typeFrame.isExact(instanceStackLocation); } if (DEBUG_METHOD_LOOKUP) { System.out.println("[receiver type is " + receiverType + ", " + (receiverTypeIsExact ? "exact]" : " not exact]")); } return resolveMethodCallTargets((ReferenceType) receiverType, invokeInstruction, cpg, receiverTypeIsExact); }
public static @CheckForNull XMethod findInvocationLeastUpperBound(InvokeInstruction inv, ConstantPoolGen cpg, JavaClassAndMethodChooser methodChooser) { if (DEBUG_METHOD_LOOKUP) { System.out.println("Find prototype method for " + SignatureConverter.convertMethodSignature(inv, cpg)); } short opcode = inv.getOpcode(); if (opcode == Constants.INVOKESTATIC) { if (methodChooser == INSTANCE_METHOD) return null; } else { if (methodChooser == STATIC_METHOD) return null; } // Find the method if (opcode == Constants.INVOKESPECIAL) { // Non-virtual dispatch return findExactMethod(inv, cpg, methodChooser); } else { String className = inv.getClassName(cpg); String methodName = inv.getName(cpg); String methodSig = inv.getSignature(cpg); if (DEBUG_METHOD_LOOKUP) { System.out.println("[Class name is " + className + "]"); System.out.println("[Method name is " + methodName + "]"); System.out.println("[Method signature is " + methodSig + "]"); } if (className.startsWith("[")) { // Java 1.5 allows array classes to appear as the class name className = "java.lang.Object"; } try { return thisOrNothing( findInvocationLeastUpperBound(getXClassFromDottedClassName(className), methodName, methodSig, opcode == Constants.INVOKESTATIC, opcode == Constants.INVOKEINTERFACE), methodChooser); } catch (CheckedAnalysisException e) { return null; } } }