@Override public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, LockSet fact) throws DataflowAnalysisException { Instruction ins = handle.getInstruction(); short opcode = ins.getOpcode(); if (opcode == Constants.MONITORENTER || opcode == Constants.MONITOREXIT) { ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock)); modifyLock(frame, fact, opcode == Constants.MONITORENTER ? 1 : -1); } else if (opcode == Constants.INVOKEVIRTUAL || opcode == Constants.INVOKEINTERFACE) { InvokeInstruction inv = (InvokeInstruction) ins; String name = inv.getMethodName(methodGen.getConstantPool()); String sig = inv.getSignature(methodGen.getConstantPool()); ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock)); if ("()V".equals(sig) && ("lock".equals(name) || "lockInterruptibly".equals(name))) { modifyLock(frame, fact, 1); } else if ("()V".equals(sig) && ("unlock".equals(name))) { modifyLock(frame, fact, -1); } } else if ((ins instanceof ReturnInstruction) && isSynchronized && !isStatic) { lockOp(fact, vna.getThisValue().getNumber(), -1); } }
/** * @param classContext * @param method */ private void analyzeMethod(ClassContext classContext, Method method) throws MethodUnprofitableException, CFGBuilderException, DataflowAnalysisException { if (method.isSynthetic() || (method.getAccessFlags() & Constants.ACC_BRIDGE) == Constants.ACC_BRIDGE) return; CFG cfg = classContext.getCFG(method); TypeDataflow typeDataflow = classContext.getTypeDataflow(method); ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen(); locationLoop: for (Iterator<Location> iter = cfg.locationIterator(); iter.hasNext(); ) { Location location = iter.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); // Only consider invoke instructions if (!(ins instanceof InvokeInstruction)) continue; if (ins instanceof INVOKEINTERFACE) continue; InvokeInstruction inv = (InvokeInstruction) ins; TypeFrame frame = typeDataflow.getFactAtLocation(location); String methodName = inv.getMethodName(constantPoolGen); if (methodName.toLowerCase().indexOf("unsupported") >= 0) continue; String methodSig = inv.getSignature(constantPoolGen); if (methodSig.equals("()Ljava/lang/UnsupportedOperationException;")) continue; Set<XMethod> targets; try { targets = Hierarchy2.resolveMethodCallTargets(inv, frame, constantPoolGen); } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } if (targets.isEmpty()) continue locationLoop; int priority = targets.size() == 1 ? Priorities.HIGH_PRIORITY : Priorities.NORMAL_PRIORITY; for (XMethod m : targets) { if (!m.isUnsupported()) continue locationLoop; XClass xc = AnalysisContext.currentXFactory().getXClass(m.getClassDescriptor()); if (!(inv instanceof INVOKESTATIC) && !(m.isFinal() || xc.isFinal())) priority = Priorities.NORMAL_PRIORITY; if (xc == null || xc.isAbstract()) { try { if (!AnalysisContext.currentAnalysisContext() .getSubtypes2() .hasSubtypes(m.getClassDescriptor())) continue locationLoop; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } } } BugInstance bug = new BugInstance(this, "DMI_UNSUPPORTED_METHOD", priority) .addClassAndMethod(classContext.getJavaClass(), method) .addCalledMethod(constantPoolGen, inv) .addSourceLine(classContext, method, location); bugReporter.reportBug(bug); } }
/** Method invocation. */ public void visitInvokeInstruction(InvokeInstruction i) { Type[] argTypes = i.getArgumentTypes(cp); for (int j = 0; j < argTypes.length; j++) cv.registerCoupling(argTypes[j]); cv.registerCoupling(i.getReturnType(cp)); /* Measuring decision: measure overloaded methods separately */ cv.registerMethodInvocation(i.getClassName(cp), i.getMethodName(cp), argTypes); }
private TaintMethodSummary getMethodSummary(InvokeInstruction obj) { String methodNameWithSig = obj.getMethodName(cpg) + obj.getSignature(cpg); String fullMethodName = getSlashedClassName(obj) + "." + methodNameWithSig; TaintMethodSummary methodSummary = methodSummaries.get(fullMethodName); if (methodSummary == null && TO_STRING_METHOD.equals(methodNameWithSig)) { methodSummary = TaintMethodSummary.getDefaultToStringSummary(); } return methodSummary; }
/** * 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 a MethodDescriptor describing the method called by given InvokeInstruction. * * @param inv the InvokeInstruction * @param cpg ConstantPoolGen of class containing instruction * @return MethodDescriptor describing the called method */ public static MethodDescriptor getCalledMethodDescriptor( InvokeInstruction inv, ConstantPoolGen cpg) { String calledClassName = inv.getClassName(cpg).replace('.', '/'); String calledMethodName = inv.getMethodName(cpg); String calledMethodSig = inv.getSignature(cpg); boolean isStatic = inv.getOpcode() == Constants.INVOKESTATIC; return DescriptorFactory.instance() .getMethodDescriptor(calledClassName, calledMethodName, calledMethodSig, isStatic); }
private static String getFullMethodName(ConstantPoolGen cpg, InvokeInstruction invoke) { String dottedClassName = invoke.getReferenceType(cpg).toString(); StringBuilder builder = new StringBuilder(ClassName.toSlashedClassName(dottedClassName)); builder.append(".").append(invoke.getMethodName(cpg)).append(invoke.getSignature(cpg)); return builder.toString(); }
private void checkForPossibleObligationTransfer( InvokeInstruction inv, InstructionHandle handle) throws ClassNotFoundException { // // We will assume that a method invocation might transfer // an obligation from one type to another if // 1. either // - it's a constructor where the constructed // type and exactly one param type // are obligation types, or // - it's a method where the return type and // exactly one param type are obligation types // 2. at least one instance of the resource "consumed" // by the transfer exists at the point of the transfer. // E.g., if we see a transfer of InputStream->Reader, // there must be an instance of InputStream at // the transfer point. // if (DEBUG_FP) { System.out.println("Checking " + handle + " as possible obligation transfer...:"); } // Find the State which is a prefix of the error state // at the location of this (possible) transfer. State transferState = getTransferState(handle); if (transferState == null) { if (DEBUG_FP) { System.out.println("No transfer state???"); } return; } String methodName = inv.getMethodName(cpg); Type producedType = methodName.equals("<init>") ? inv.getReferenceType(cpg) : inv.getReturnType(cpg); if (DEBUG_FP && !(producedType instanceof ObjectType)) { System.out.println("Produced type " + producedType + " not an ObjectType"); } if (producedType instanceof ObjectType) { Obligation produced = database.getFactory().getObligationByType((ObjectType) producedType); if (DEBUG_FP && produced == null) { System.out.println("Produced type " + producedType + " not an obligation type"); } if (produced != null) { XMethod calledMethod = XFactory.createXMethod(inv, cpg); Obligation[] params = database.getFactory().getParameterObligationTypes(calledMethod); for (int i = 0; i < params.length; i++) { Obligation consumed = params[i]; if (DEBUG_FP && consumed == null) { System.out.println("Param " + i + " not an obligation type"); } if (DEBUG_FP && consumed != null && consumed.equals(produced)) { System.out.println("Consumed type is the same as produced type"); } if (consumed != null && !consumed.equals(produced)) { // See if an instance of the consumed obligation // type // exists here. if (transferState.getObligationSet().getCount(consumed.getId()) > 0) { transferList.add(new PossibleObligationTransfer(consumed, produced)); if (DEBUG_FP) { System.out.println( "===> Possible transfer of " + consumed + " to " + produced + " at " + handle); } } else if (DEBUG_FP) { System.out.println( handle + " not a transfer " + "of " + consumed + "->" + produced + " because no instances of " + consumed); System.out.println("I see " + transferState.getObligationSet()); } } } } } }