Example #1
0
  @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);
    }
  }
Example #2
0
 public LockAnalysis(MethodGen methodGen, ValueNumberDataflow vnaDataflow, DepthFirstSearch dfs) {
   super(dfs);
   this.methodGen = methodGen;
   this.vnaDataflow = vnaDataflow;
   this.vna = vnaDataflow.getAnalysis();
   this.isSynchronized = methodGen.isSynchronized();
   this.isStatic = methodGen.isStatic();
   if (DEBUG) {
     System.out.println(
         "Analyzing Locks in " + methodGen.getClassName() + "." + methodGen.getName());
   }
 }
  /**
   * Find out if any VNs in the source block contribute to unconditionally dereferenced VNs in the
   * target block. If so, the VN in the source block is also unconditionally dereferenced, and we
   * must propagate the target VN's dereferences.
   *
   * @param fact a dataflow value
   * @param edge edge to check for merge input values
   * @return possibly-modified dataflow value
   */
  private UnconditionalValueDerefSet propagateDerefSetsToMergeInputValues(
      UnconditionalValueDerefSet fact, Edge edge) {

    ValueNumberFrame blockValueNumberFrame = vnaDataflow.getResultFact(edge.getSource());
    ValueNumberFrame targetValueNumberFrame = vnaDataflow.getStartFact(edge.getTarget());

    UnconditionalValueDerefSet originalFact = fact;
    fact = duplicateFact(fact);

    if (blockValueNumberFrame.isValid() && targetValueNumberFrame.isValid()) {
      int slots = 0;
      if (targetValueNumberFrame.getNumSlots() == blockValueNumberFrame.getNumSlots()) {
        slots = targetValueNumberFrame.getNumSlots();
      } else if (targetValueNumberFrame.getNumLocals() == blockValueNumberFrame.getNumLocals()) {
        slots = targetValueNumberFrame.getNumLocals();
      }

      if (slots > 0) {
        if (DEBUG) {
          System.out.println("** Valid VNA frames for " + edge);
          System.out.println("** Block : " + blockValueNumberFrame);
          System.out.println("** Target: " + targetValueNumberFrame);
        }

        for (int i = 0; i < slots; i++) {
          ValueNumber blockVN = blockValueNumberFrame.getValue(i);
          ValueNumber targetVN = targetValueNumberFrame.getValue(i);
          if (blockVN.equals(targetVN)) {
            continue;
          }
          fact.clearDerefSet(blockVN);
          if (originalFact.isUnconditionallyDereferenced(targetVN)) {
            fact.setDerefSet(blockVN, originalFact.getUnconditionalDerefLocationSet(targetVN));
          }
        } // for all slots

        for (ValueNumber blockVN : blockValueNumberFrame.valueNumbersForLoads()) {
          AvailableLoad load = blockValueNumberFrame.getLoad(blockVN);
          if (load == null) {
            continue;
          }
          ValueNumber[] targetVNs = targetValueNumberFrame.getAvailableLoad(load);
          if (targetVNs != null) {
            for (ValueNumber targetVN : targetVNs) {
              if (targetVN.hasFlag(ValueNumber.PHI_NODE)
                  && fact.isUnconditionallyDereferenced(targetVN)
                  && !fact.isUnconditionallyDereferenced(blockVN)) {
                // Block VN is also dereferenced
                // unconditionally.
                AvailableLoad targetLoad = targetValueNumberFrame.getLoad(targetVN);
                if (!load.equals(targetLoad)) {
                  continue;
                }
                if (DEBUG) {
                  System.out.println(
                      "** Copy vn derefs for " + load + " from " + targetVN + " --> " + blockVN);
                  System.out.println(
                      "** block phi for "
                          + System.identityHashCode(blockValueNumberFrame)
                          + " is "
                          + blockValueNumberFrame.phiNodeForLoads);
                  System.out.println(
                      "** target phi for "
                          + System.identityHashCode(targetValueNumberFrame)
                          + " is "
                          + targetValueNumberFrame.phiNodeForLoads);
                }
                fact.setDerefSet(blockVN, fact.getUnconditionalDerefLocationSet(targetVN));
              }
            }
          }
        }
      }
    }
    if (DEBUG) {
      System.out.println("Target VNF: " + targetValueNumberFrame);
      System.out.println("Block VNF: " + blockValueNumberFrame);
      System.out.println("fact: " + fact);
    }
    fact.cleanDerefSet(null, blockValueNumberFrame);
    return fact;
  }
  public void meetInto(
      UnconditionalValueDerefSet fact,
      Edge edge,
      UnconditionalValueDerefSet result,
      boolean onlyEdge) {
    if (isExceptionEdge(edge) && !onlyEdge) {
      if (DEBUG) {
        System.out.println("Skipping exception edge");
      }
      return;
    }

    ValueNumber knownNonnullOnBranch = null;
    // Edge transfer function
    if (isFactValid(fact)) {
      fact = propagateDerefSetsToMergeInputValues(fact, edge);
      if (invDataflow != null) {
        knownNonnullOnBranch = findValueKnownNonnullOnBranch(fact, edge);
        if (knownNonnullOnBranch != null) {
          fact = duplicateFact(fact);
          fact.clearDerefSet(knownNonnullOnBranch);
        }
      }
    }
    boolean isBackEdge = edge.isBackwardInBytecode();
    Set<Integer> loopExitBranches = ClassContext.getLoopExitBranches(method, methodGen);
    assert loopExitBranches != null;
    boolean sourceIsTopOfLoop = edge.sourceIsTopOfLoop(loopExitBranches);
    if (sourceIsTopOfLoop && edge.getType() == EdgeTypes.FALL_THROUGH_EDGE) {
      isBackEdge = true;
    }
    /*
    if (false && (edge.getType() == EdgeTypes.IFCMP_EDGE || sourceIsTopOfLoop)) {
        System.out.println("Meet into " + edge);
        System.out.println("  foo2: " + sourceIsTopOfLoop);
        System.out.println("  getType: " + edge.getType());
        System.out.println("  Backedge according to bytecode: " + isBackEdge);
        System.out.println("  Fact hashCode: " + System.identityHashCode(result));
        System.out.println("  Initial fact: " + result);
        System.out.println("  Edge fact: " + fact);
    }
     */
    if (result.isTop() || fact.isBottom()) {
      // Make result identical to other fact
      copy(fact, result);
      if (ASSUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
        result.resultsFromBackEdge = true;
      }
    } else if (ASSUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
      result.unionWith(fact, vnaDataflow.getAnalysis().getFactory());
      result.resultsFromBackEdge = true;
      if (DEBUG) {
        System.out.println(
            "\n Forcing union of " + System.identityHashCode(result) + " due to backedge info");
        System.out.println("  result: " + result);
      }

    } else if (result.isBottom() || fact.isTop()) {
      // No change in result fact
    } else {
      // Dataflow merge
      // (intersection of unconditional deref values)
      if (ASSUME_NONZERO_TRIP_LOOPS && result.resultsFromBackEdge) {
        result.backEdgeUpdateCount++;
        if (result.backEdgeUpdateCount < 10) {
          if (DEBUG) {
            System.out.println(
                "\n Union update of " + System.identityHashCode(result) + " due to backedge info");
          }
          result.unionWith(fact, vnaDataflow.getAnalysis().getFactory());
          return;
        }
      }
      result.mergeWith(fact, knownNonnullOnBranch, vnaDataflow.getAnalysis().getFactory());
      if (DEBUG) {
        System.out.println("  updated: " + System.identityHashCode(result));
        System.out.println("  result: " + result);
      }
    }
    if (DEBUG && isBackEdge && edge.getType() == EdgeTypes.IFCMP_EDGE) {
      System.out.println("  result: " + result);
    }
  }
 @Override
 public UnconditionalValueDerefSet createFact() {
   return new UnconditionalValueDerefSet(vnaDataflow.getAnalysis().getNumValuesAllocated());
 }
  @Override
  public void transferInstruction(
      InstructionHandle handle, BasicBlock basicBlock, UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {

    Instruction instruction = handle.getInstruction();
    if (fact.isTop()) {
      return;
    }
    Location location = new Location(handle, basicBlock);

    // If this is a call to an assertion method,
    // change the dataflow value to be TOP.
    // We don't want to report future derefs that would
    // be guaranteed only if the assertion methods
    // returns normally.
    // TODO: at some point, evaluate whether we should revisit this
    if (isAssertion(handle) // || handle.getInstruction() instanceof ATHROW
    ) {
      if (DEBUG) {
        System.out.println("MAKING BOTTOM0 AT: " + location);
      }
      fact.clear();
      return;
    }

    // Get value number frame
    ValueNumberFrame vnaFrame = vnaDataflow.getFactAtLocation(location);
    if (!vnaFrame.isValid()) {
      if (DEBUG) {
        System.out.println("MAKING TOP1 AT: " + location);
      }
      // Probably dead code.
      // Assume this location can't be reached.
      makeFactTop(fact);
      return;
    }
    if (isNullCheck(handle, methodGen.getConstantPool())) {
      handleNullCheck(location, vnaFrame, fact);
    }

    // Check for calls to a method that unconditionally dereferences
    // a parameter. Mark any such arguments as derefs.
    if (CHECK_CALLS && instruction instanceof InvokeInstruction) {
      checkUnconditionalDerefDatabase(location, vnaFrame, fact);
    }

    // If this is a method call instruction,
    // check to see if any of the parameters are @NonNull,
    // and treat them as dereferences.
    if (CHECK_ANNOTATIONS && instruction instanceof InvokeInstruction) {
      checkNonNullParams(location, vnaFrame, fact);
    }

    if (CHECK_ANNOTATIONS && instruction instanceof ARETURN) {
      XMethod thisMethod = XFactory.createXMethod(methodGen);
      checkNonNullReturnValue(thisMethod, location, vnaFrame, fact);
    }

    if (CHECK_ANNOTATIONS
        && (instruction instanceof PUTFIELD || instruction instanceof PUTSTATIC)) {
      checkNonNullPutField(location, vnaFrame, fact);
    }

    // Check to see if an instance value is dereferenced here
    checkInstance(location, vnaFrame, fact);

    /*
    if (false) {
        fact.cleanDerefSet(location, vnaFrame);
    }*/

    if (DEBUG && fact.isTop()) {
      System.out.println("MAKING TOP2 At: " + location);
    }
  }
  private void analyzeMethod(ClassContext classContext, Method method)
      throws CFGBuilderException, DataflowAnalysisException {
    if (isSynthetic(method) || !prescreen(classContext, method)) return;
    XMethod xmethod = XFactory.createXMethod(classContext.getJavaClass(), method);
    if (xmethod.isSynthetic()) return;

    BugAccumulator accumulator = new BugAccumulator(bugReporter);

    CFG cfg = classContext.getCFG(method);
    TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
    ValueNumberDataflow vnDataflow = classContext.getValueNumberDataflow(method);

    ConstantPoolGen cpg = classContext.getConstantPoolGen();
    MethodGen methodGen = classContext.getMethodGen(method);
    if (methodGen == null) return;
    String fullMethodName = methodGen.getClassName() + "." + methodGen.getName();

    String sourceFile = classContext.getJavaClass().getSourceFileName();
    if (DEBUG) {
      System.out.println("\n" + fullMethodName);
    }

    // Process each instruction
    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;

      InvokeInstruction inv = (InvokeInstruction) ins;

      XMethod invokedMethod = XFactory.createXMethod(inv, cpg);

      String invokedMethodName = invokedMethod.getName();
      String argSignature = invokedMethod.getSignature();
      argSignature = argSignature.substring(0, argSignature.indexOf(')') + 1);
      String call = invokedMethodName + argSignature;
      SignatureParser sigParser = new SignatureParser(inv.getSignature(cpg));

      Collection<Info> collection = callMap.get(call);
      if (!callMap.containsKey(call)) continue;
      for (Info info : collection) {
        Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2();
        if (DEBUG)
          System.out.println(
              "at "
                  + handle.getPosition()
                  + " Checking call to "
                  + info.interfaceForCall
                  + " : "
                  + invokedMethod);
        try {
          if (!subtypes2.isSubtype(invokedMethod.getClassDescriptor(), info.interfaceForCall))
            continue;
        } catch (ClassNotFoundException e) {
          if (info.interfaceForCall.getClassName().equals("java/util/Collection")
              && invokedMethod.getClassName().equals("com.google.common.collect.Multiset")) {
            assert true;
            // we know this is OK without needing to find definition of Multiset
          } else {
            AnalysisContext.reportMissingClass(e);
            continue;
          }
        }

        boolean allMethod;

        int typeArgument;
        if (info.typeIndex >= 0) {
          allMethod = false;
          typeArgument = info.typeIndex;
        } else {
          allMethod = true;
          typeArgument = -(1 + info.typeIndex);
        }
        int pos = info.argumentIndex;

        int lhsPos;
        if (inv instanceof INVOKESTATIC) lhsPos = sigParser.getSlotsFromTopOfStackForParameter(0);
        else lhsPos = sigParser.getTotalArgumentSize();

        int stackPos = sigParser.getSlotsFromTopOfStackForParameter(pos);

        TypeFrame frame = typeDataflow.getFactAtLocation(location);
        if (!frame.isValid()) {
          // This basic block is probably dead
          continue;
        }

        Type operandType = frame.getStackValue(stackPos);
        if (operandType.equals(TopType.instance())) {
          // unreachable
          continue;
        }

        if (operandType.equals(NullType.instance())) {
          // ignore
          continue;
        }

        ValueNumberFrame vnFrame = vnDataflow.getFactAtLocation(location);

        if (!vnFrame.isValid()) {
          AnalysisContext.logError("Invalid value number frame in " + xmethod);
          continue;
        }

        ValueNumber objectVN = vnFrame.getStackValue(lhsPos);
        ValueNumber argVN = vnFrame.getStackValue(stackPos);

        if (objectVN.equals(argVN)) {
          String bugPattern = "DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES";
          int priority = HIGH_PRIORITY;
          if (invokedMethodName.equals("removeAll")) {
            bugPattern = "DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION";
            priority = NORMAL_PRIORITY;
          } else if (invokedMethodName.endsWith("All")) {
            bugPattern = "DMI_VACUOUS_SELF_COLLECTION_CALL";
            priority = NORMAL_PRIORITY;
          }
          if (invokedMethodName.startsWith("contains")) {
            InstructionHandle next = handle.getNext();
            if (next != null) {
              Instruction nextIns = next.getInstruction();

              if (nextIns instanceof InvokeInstruction) {
                XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg);
                if (nextMethod.getName().equals("assertFalse")) continue;
              }
            }
          }
          accumulator.accumulateBug(
              new BugInstance(this, bugPattern, priority)
                  .addClassAndMethod(methodGen, sourceFile)
                  .addCalledMethod(methodGen, (InvokeInstruction) ins)
                  .addOptionalAnnotation(
                      ValueNumberSourceInfo.findAnnotationFromValueNumber(
                          method, location, objectVN, vnFrame, "INVOKED_ON")),
              SourceLineAnnotation.fromVisitedInstruction(
                  classContext, methodGen, sourceFile, handle));
        }

        // Only consider generic...
        Type objectType = frame.getStackValue(lhsPos);
        if (!(objectType instanceof GenericObjectType)) continue;

        GenericObjectType operand = (GenericObjectType) objectType;

        int expectedTypeParameters = 1;
        String simpleName = info.interfaceForCall.getSimpleName();
        if (simpleName.toLowerCase().endsWith("map") || simpleName.equals("Hashtable"))
          expectedTypeParameters = 2;
        else if (simpleName.equals("Table")) expectedTypeParameters = 3;

        // ... containers
        if (!operand.hasParameters()) continue;
        if (operand.getNumParameters() != expectedTypeParameters) continue;
        ClassDescriptor operandClass = DescriptorFactory.getClassDescriptor(operand);
        if (!isGenericCollection(operandClass)) continue;

        if (expectedTypeParameters == 2
            && Subtypes2.instanceOf(operandClass, Map.class)
            && !TypeFrameModelingVisitor.isStraightGenericMap(operandClass)) continue;
        Type expectedType;
        if (allMethod) expectedType = operand;
        else expectedType = operand.getParameterAt(typeArgument);
        Type actualType = frame.getStackValue(stackPos);
        Type equalsType = actualType;
        if (allMethod) {
          if (!(actualType instanceof GenericObjectType)) {
            continue;
          }
          equalsType = ((GenericObjectType) actualType).getParameterAt(typeArgument);
        }

        IncompatibleTypes matchResult = compareTypes(expectedType, actualType, allMethod);

        boolean parmIsObject = expectedType.getSignature().equals("Ljava/lang/Object;");
        boolean selfOperation = !allMethod && operand.equals(actualType) && !parmIsObject;
        if (!allMethod && !parmIsObject && actualType instanceof GenericObjectType) {

          GenericObjectType p2 = (GenericObjectType) actualType;
          List<? extends ReferenceType> parameters = p2.getParameters();
          if (parameters != null && parameters.equals(operand.getParameters()))
            selfOperation = true;
        }

        if (!selfOperation
            && (matchResult == IncompatibleTypes.SEEMS_OK
                || matchResult.getPriority() == Priorities.IGNORE_PRIORITY)) continue;

        if (invokedMethodName.startsWith("contains") || invokedMethodName.equals("remove")) {
          InstructionHandle next = handle.getNext();
          if (next != null) {
            Instruction nextIns = next.getInstruction();

            if (nextIns instanceof InvokeInstruction) {
              XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg);
              if (nextMethod.getName().equals("assertFalse")) continue;
            }
          }
        } else if (invokedMethodName.equals("get") || invokedMethodName.equals("remove")) {
          InstructionHandle next = handle.getNext();
          if (next != null) {
            Instruction nextIns = next.getInstruction();

            if (nextIns instanceof InvokeInstruction) {
              XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg);
              if (nextMethod.getName().equals("assertNull")) continue;
            }
          }
        }
        boolean noisy = false;
        if (invokedMethodName.equals("get")) {
          UnconditionalValueDerefDataflow unconditionalValueDerefDataflow =
              classContext.getUnconditionalValueDerefDataflow(method);

          UnconditionalValueDerefSet unconditionalDeref =
              unconditionalValueDerefDataflow.getFactAtLocation(location);
          ValueNumberFrame vnAfter = vnDataflow.getFactAfterLocation(location);
          ValueNumber top = vnAfter.getTopValue();
          noisy =
              unconditionalDeref.getValueNumbersThatAreUnconditionallyDereferenced().contains(top);
        }
        // Prepare bug report
        SourceLineAnnotation sourceLineAnnotation =
            SourceLineAnnotation.fromVisitedInstruction(
                classContext, methodGen, sourceFile, handle);

        // Report a bug that mentions each of the failed arguments in
        // matches

        if (expectedType instanceof GenericObjectType)
          expectedType = ((GenericObjectType) expectedType).getUpperBound();

        int priority = matchResult.getPriority();
        if (!operandClass.getClassName().startsWith("java/util")
            && priority == Priorities.HIGH_PRIORITY)
          priority = Math.max(priority, Priorities.NORMAL_PRIORITY);
        if (TestCaseDetector.likelyTestCase(xmethod))
          priority = Math.max(priority, Priorities.NORMAL_PRIORITY);
        else if (selfOperation) priority = Priorities.HIGH_PRIORITY;
        ClassDescriptor expectedClassDescriptor =
            DescriptorFactory.createClassOrObjectDescriptorFromSignature(
                expectedType.getSignature());
        ClassDescriptor actualClassDescriptor =
            DescriptorFactory.createClassOrObjectDescriptorFromSignature(equalsType.getSignature());
        ClassSummary classSummary = AnalysisContext.currentAnalysisContext().getClassSummary();
        Set<XMethod> targets = null;
        try {
          targets =
              Hierarchy2.resolveVirtualMethodCallTargets(
                  actualClassDescriptor, "equals", "(Ljava/lang/Object;)Z", false, false);
          boolean allOk = targets.size() > 0;
          for (XMethod m2 : targets)
            if (!classSummary.mightBeEqualTo(m2.getClassDescriptor(), expectedClassDescriptor))
              allOk = false;
          if (allOk) priority += 2;
        } catch (ClassNotFoundException e) {
          AnalysisContext.reportMissingClass(e);
        }
        String bugPattern = "GC_UNRELATED_TYPES";

        BugInstance bug =
            new BugInstance(this, bugPattern, priority)
                .addClassAndMethod(methodGen, sourceFile)
                .addFoundAndExpectedType(actualType, expectedType)
                .addCalledMethod(methodGen, (InvokeInstruction) ins)
                .addOptionalAnnotation(
                    ValueNumberSourceInfo.findAnnotationFromValueNumber(
                        method, location, objectVN, vnFrame, "INVOKED_ON"))
                .addOptionalAnnotation(
                    ValueNumberSourceInfo.findAnnotationFromValueNumber(
                        method, location, argVN, vnFrame, "ARGUMENT"))
                .addEqualsMethodUsed(targets);
        if (noisy) {
          WarningPropertySet<WarningProperty> propertySet =
              new WarningPropertySet<WarningProperty>();

          propertySet.addProperty(GeneralWarningProperty.NOISY_BUG);
          propertySet.decorateBugInstance(bug);
        }
        accumulator.accumulateBug(bug, sourceLineAnnotation);
      }
    }
    accumulator.reportAccumulatedBugs();
  }