/**
   * @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);
    }
  }
  private void compute() {
    if (defined == null) {
      // System.out.println("Computing");
      defined = new HashSet<String>();

      Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2();
      Collection<XClass> allClasses = subtypes2.getXClassCollection();

      IAnalysisCache analysisCache = Global.getAnalysisCache();

      for (XClass c : allClasses) {
        try {
          JavaClass jclass =
              analysisCache.getClassAnalysis(JavaClass.class, c.getClassDescriptor());
          addAllDefinitions(jclass);
        } catch (MissingClassException e) {
          bugReporter.reportMissingClass(e.getClassDescriptor());
        } catch (CheckedAnalysisException e) {
          bugReporter.logError(
              "Could not find class " + c.getClassDescriptor().toDottedClassName(), e);
        }
      }
      // System.out.println("Done Computing: " +
      // defined.contains("edu.umd.cs.findbugs.ba.IsNullValueAnalysis.UNKNOWN_VALUES_ARE_NSP : Z"));
    }
  }
  private boolean isGenericCollection(ClassDescriptor operandClass) {
    String dottedClassName = operandClass.getDottedClassName();

    if (baseGenericTypes.contains(dottedClassName)) return true;

    String found = null;
    for (String c : baseGenericTypes) {
      if (Subtypes2.instanceOf(operandClass, c)) {
        found = c;
        break;
      }
    }
    if (found == null) return false;
    if (dottedClassName.startsWith("java.util.")
        || dottedClassName.startsWith("com.google.common.collect.")) return true;
    try {
      XClass xclass = Global.getAnalysisCache().getClassAnalysis(XClass.class, operandClass);

      String sig = xclass.getSourceSignature();
      if (sig == null) return false;

      String typeParameter = null;
      List<String> split = GenericUtilities.split(sig, true);
      if (sig.charAt(0) == '<') {
        int end = sig.indexOf(':');
        if (end > 0) typeParameter = sig.substring(1, end);
      }
      if (DEBUG) System.out.println(dottedClassName + " " + typeParameter + " " + split);
      for (String s : split) {
        int i = s.indexOf('<');
        if (i < 0) continue;
        if (s.charAt(0) != 'L') throw new IllegalStateException("unexpected non signature: " + s);
        ClassDescriptor c = DescriptorFactory.createClassDescriptor(s.substring(1, i));
        String superTypeParameter = s.substring(i + 1);
        if (isGenericCollection(c)
            && (typeParameter == null || superTypeParameter.startsWith("T" + typeParameter))) {
          if (DEBUG) System.out.println(operandClass + " is a subtype of " + s);
          return true;
        }
      }
      if (DEBUG) System.out.println("Not a subtype");

    } catch (CheckedAnalysisException e1) {
      AnalysisContext.logError(
          "Error checking for weird generic parameterization of " + operandClass, e1);
    }
    return false;
  }
Exemplo n.º 4
0
  private boolean isJunit3TestCase(XClass jClass) throws ClassNotFoundException {
    ClassDescriptor sDesc = jClass.getSuperclassDescriptor();
    if (sDesc == null) {
      return false;
    }
    String sName = sDesc.getClassName();
    if (sName.equals("junit/framework/TestCase")) {
      return true;
    }
    if (sName.equals("java/lang/Object")) {
      return false;
    }

    try {
      XClass sClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, sDesc);
      if (sClass == null) {
        return false;
      }
      return isJunit3TestCase(sClass);
    } catch (CheckedAnalysisException e) {
      return false;
    }
  }
  @Override
  public void visit(Method obj) {

    int accessFlags = obj.getAccessFlags();
    boolean isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
    if (getMethodName().equals("<init>")
        && getMethodSig().equals("()V")
        && (accessFlags & ACC_PUBLIC) != 0) hasPublicVoidConstructor = true;
    if (!getMethodName().equals("<init>") && isSynthetic(obj)) foundSynthetic = true;
    // System.out.println(methodName + isSynchronized);

    if (getMethodName().equals("readExternal")
        && getMethodSig().equals("(Ljava/io/ObjectInput;)V")) {
      sawReadExternal = true;
      if (DEBUG && !obj.isPrivate())
        System.out.println("Non-private readExternal method in: " + getDottedClassName());
    } else if (getMethodName().equals("writeExternal")
        && getMethodSig().equals("(Ljava/io/Objectoutput;)V")) {
      sawWriteExternal = true;
      if (DEBUG && !obj.isPrivate())
        System.out.println("Non-private writeExternal method in: " + getDottedClassName());
    } else if (getMethodName().equals("readResolve")
        && getMethodSig().startsWith("()")
        && isSerializable) {
      sawReadResolve = true;
      if (!getMethodSig().equals("()Ljava/lang/Object;"))
        bugReporter.reportBug(
            new BugInstance(this, "SE_READ_RESOLVE_MUST_RETURN_OBJECT", HIGH_PRIORITY)
                .addClassAndMethod(this));
      else if (obj.isStatic())
        bugReporter.reportBug(
            new BugInstance(this, "SE_READ_RESOLVE_IS_STATIC", HIGH_PRIORITY)
                .addClassAndMethod(this));
      else if (obj.isPrivate())
        try {
          Set<ClassDescriptor> subtypes =
              AnalysisContext.currentAnalysisContext()
                  .getSubtypes2()
                  .getSubtypes(getClassDescriptor());
          if (subtypes.size() > 1) {
            BugInstance bug =
                new BugInstance(this, "SE_PRIVATE_READ_RESOLVE_NOT_INHERITED", NORMAL_PRIORITY)
                    .addClassAndMethod(this);
            boolean nasty = false;
            for (ClassDescriptor subclass : subtypes)
              if (!subclass.equals(getClassDescriptor())) {

                XClass xSub = AnalysisContext.currentXFactory().getXClass(subclass);
                if (xSub != null
                    && xSub.findMethod("readResolve", "()Ljava/lang/Object;", false) == null
                    && xSub.findMethod("writeReplace", "()Ljava/lang/Object;", false) == null) {
                  bug.addClass(subclass).describe(ClassAnnotation.SUBCLASS_ROLE);
                  nasty = true;
                }
              }
            if (nasty) bug.setPriority(HIGH_PRIORITY);
            else if (!getThisClass().isPublic()) bug.setPriority(LOW_PRIORITY);
            bugReporter.reportBug(bug);
          }

        } catch (ClassNotFoundException e) {
          bugReporter.reportMissingClass(e);
        }

    } else if (getMethodName().equals("readObject")
        && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V")
        && isSerializable) {
      sawReadObject = true;
      if (!obj.isPrivate())
        bugReporter.reportBug(
            new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY)
                .addClassAndMethod(this));

    } else if (getMethodName().equals("readObjectNoData")
        && getMethodSig().equals("()V")
        && isSerializable) {

      if (!obj.isPrivate())
        bugReporter.reportBug(
            new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY)
                .addClassAndMethod(this));

    } else if (getMethodName().equals("writeObject")
        && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V")
        && isSerializable) {
      sawWriteObject = true;
      if (!obj.isPrivate())
        bugReporter.reportBug(
            new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY)
                .addClassAndMethod(this));
    }

    if (isSynchronized) {
      if (getMethodName().equals("readObject")
          && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V")
          && isSerializable)
        bugReporter.reportBug(
            new BugInstance(this, "RS_READOBJECT_SYNC", NORMAL_PRIORITY).addClass(this));
      else if (getMethodName().equals("writeObject")
          && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V")
          && isSerializable) writeObjectIsSynchronized = true;
      else foundSynchronizedMethods = true;
    }
    super.visit(obj);
  }
  @Override
  public void visit(JavaClass obj) {
    String superClassname = obj.getSuperclassName();
    // System.out.println("superclass of " + getClassName() + " is " + superClassname);
    isEnum = superClassname.equals("java.lang.Enum");
    if (isEnum) return;
    int flags = obj.getAccessFlags();
    isAbstract = (flags & ACC_ABSTRACT) != 0 || (flags & ACC_INTERFACE) != 0;
    isAnonymousInnerClass = anonymousInnerClassNamePattern.matcher(getClassName()).matches();
    innerClassHasOuterInstance = false;
    for (Field f : obj.getFields()) {
      if (f.getName().equals("this$0")) {
        innerClassHasOuterInstance = true;
        break;
      }
    }

    sawSerialVersionUID = false;
    isSerializable = implementsSerializableDirectly = false;
    isExternalizable = false;
    directlyImplementsExternalizable = false;
    isGUIClass = false;
    isEjbImplClass = false;
    seenTransientField = false;
    // boolean isEnum = obj.getSuperclassName().equals("java.lang.Enum");
    fieldsThatMightBeAProblem.clear();
    transientFieldsUpdates.clear();
    transientFieldsSetInConstructor.clear();
    transientFieldsSetToDefaultValueInConstructor.clear();
    // isRemote = false;

    // Does this class directly implement Serializable?
    String[] interface_names = obj.getInterfaceNames();
    for (String interface_name : interface_names) {
      if (interface_name.equals("java.io.Externalizable")) {
        directlyImplementsExternalizable = true;
        isExternalizable = true;
        if (DEBUG) {
          System.out.println("Directly implements Externalizable: " + getClassName());
        }
      } else if (interface_name.equals("java.io.Serializable")) {
        implementsSerializableDirectly = true;
        isSerializable = true;
        if (DEBUG) {
          System.out.println("Directly implements Serializable: " + getClassName());
        }
        break;
      }
    }

    // Does this class indirectly implement Serializable?
    if (!isSerializable) {
      if (Subtypes2.instanceOf(obj, "java.io.Externalizable")) {
        isExternalizable = true;
        if (DEBUG) {
          System.out.println("Indirectly implements Externalizable: " + getClassName());
        }
      }
      if (Subtypes2.instanceOf(obj, "java.io.Serializable")) {
        isSerializable = true;
        if (DEBUG) {
          System.out.println("Indirectly implements Serializable: " + getClassName());
        }
      }
    }

    hasPublicVoidConstructor = false;
    superClassHasVoidConstructor = true;
    superClassHasReadObject = false;
    superClassImplementsSerializable = isSerializable && !implementsSerializableDirectly;
    ClassDescriptor superclassDescriptor = getXClass().getSuperclassDescriptor();
    if (superclassDescriptor != null)
      try {
        XClass superXClass =
            Global.getAnalysisCache().getClassAnalysis(XClass.class, superclassDescriptor);
        if (superXClass != null) {
          superClassImplementsSerializable =
              AnalysisContext.currentAnalysisContext()
                  .getSubtypes2()
                  .isSubtype(
                      superXClass.getClassDescriptor(),
                      DescriptorFactory.createClassDescriptor(java.io.Serializable.class));
          superClassHasVoidConstructor = false;
          for (XMethod m : superXClass.getXMethods()) {
            if (m.getName().equals("<init>") && m.getSignature().equals("()V") && !m.isPrivate()) {
              superClassHasVoidConstructor = true;
            }
            if (m.getName().equals("readObject")
                && m.getSignature().equals("(Ljava/io/ObjectInputStream;)V")
                && m.isPrivate()) superClassHasReadObject = true;
          }
        }
      } catch (ClassNotFoundException e) {
        bugReporter.reportMissingClass(e);
      } catch (CheckedAnalysisException e) {
        bugReporter.logError("huh", e);
      }

    // Is this a GUI  or other class that is rarely serialized?

    isGUIClass = false;
    isEjbImplClass = false;
    if (true || !directlyImplementsExternalizable && !implementsSerializableDirectly) {
      isEjbImplClass = Subtypes2.instanceOf(obj, "javax.ejb.SessionBean");
      isGUIClass =
          (Subtypes2.instanceOf(obj, "java.lang.Throwable")
              || Subtypes2.instanceOf(obj, "java.awt.Component")
              || Subtypes2.instanceOf(obj, "java.awt.Component$AccessibleAWTComponent")
              || Subtypes2.instanceOf(obj, "java.awt.event.ActionListener")
              || Subtypes2.instanceOf(obj, "java.util.EventListener"));
      if (!isGUIClass) {
        JavaClass o = obj;
        while (o != null) {
          if (o.getClassName().startsWith("java.awt")
              || o.getClassName().startsWith("javax.swing")) {
            isGUIClass = true;
            break;
          }
          try {
            o = o.getSuperClass();
          } catch (ClassNotFoundException e) {
            break;
          }
        }
      }
    }

    foundSynthetic = false;
    foundSynchronizedMethods = false;
    writeObjectIsSynchronized = false;

    sawReadExternal = sawWriteExternal = sawReadObject = sawReadResolve = sawWriteObject = false;
    if (isSerializable) {
      for (Method m : obj.getMethods()) {

        if (m.getName().equals("readObject")
            && m.getSignature().equals("(Ljava/io/ObjectInputStream;)V")) sawReadObject = true;
        else if (m.getName().equals("readResolve") && m.getSignature().startsWith("()"))
          sawReadResolve = true;
        else if (m.getName().equals("readObjectNoData") && m.getSignature().equals("()V"))
          sawReadObject = true;
        else if (m.getName().equals("writeObject")
            && m.getSignature().equals("(Ljava/io/ObjectOutputStream;)V")) sawWriteObject = true;
      }
      for (Field f : obj.getFields()) {
        if (f.isTransient()) seenTransientField = true;
      }
    }
  }
Exemplo n.º 7
0
 /**
  * This is the "dumb" version of the detector. It may generate false positives, and/or not detect
  * all instances of the bug.
  *
  * @see edu.umd.cs.findbugs.visitclass.DismantleBytecode#sawOpcode(int)
  */
 @Override
 public void sawOpcode(int seen) {
   if (DEBUG) {
     System.out.println(getPC() + " " + OPCODE_NAMES[seen]);
   }
   switch (seen) {
     case IFNE:
     case IFEQ:
       {
         OpcodeStack.Item top = stack.getStackItem(0);
         if (DEBUG) {
           System.out.println("Stack top: " + top);
         }
         XMethod m = top.getReturnValueOf();
         if (m != null
             && m.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
             && m.getName().equals("containsKey")) {
           lastQuestionableCheckTarget = getBranchTarget();
           if (seen == IFEQ) {
             priority = LOW_PRIORITY;
           } else if (seen == IFNE) {
             priority = NORMAL_PRIORITY;
           }
         }
         break;
       }
     case IFNULL:
     case IFNONNULL:
       {
         OpcodeStack.Item top = stack.getStackItem(0);
         if (DEBUG) {
           System.out.println("Stack top: " + top);
         }
         XMethod m = top.getReturnValueOf();
         if (DEBUG) {
           System.out.println("Found null check");
         }
         if (m != null
             && m.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
             && m.getName().equals("get")) {
           lastQuestionableCheckTarget = getBranchTarget();
           if (seen == IFNULL) {
             priority = LOW_PRIORITY;
           } else if (seen == IFNONNULL) {
             priority = NORMAL_PRIORITY;
           }
         }
         break;
       }
     case INVOKEVIRTUAL:
     case INVOKEINTERFACE:
       {
         if (getDottedClassConstantOperand().equals("java.util.concurrent.ConcurrentHashMap")) {
           String methodName = getNameConstantOperand();
           XClass xClass = getXClassOperand();
           if (xClass != null && methodName.equals("put")) {
             if ((getPC() < lastQuestionableCheckTarget) && (lastQuestionableCheckTarget != -1)) {
               bugReporter.reportBug(
                   new BugInstance(
                           this, "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", priority)
                       .addClassAndMethod(this)
                       .addType(xClass.getClassDescriptor())
                       .addCalledMethod(this)
                       .addSourceLine(this));
             }
           }
         }
         break;
       }
   }
 }
  private TypeQualifierValue(ClassDescriptor typeQualifier, @CheckForNull Object value) {
    this.typeQualifier = typeQualifier;
    this.value = value;
    boolean isStrict = false; // will be set to true if this is a strict
    // type qualifier value
    boolean isExclusive = false; // will be set to true if this is an
    // exclusive type qualifier value
    boolean isExhaustive = false; // will be set to true if this is an
    // exhaustive type qualifier value

    TypeQualifierValidator<A> validator = null;
    Class<A> qualifierClass = null;
    A proxy = null;
    try {
      XClass xclass = Global.getAnalysisCache().getClassAnalysis(XClass.class, typeQualifier);

      // Annotation elements appear as abstract methods in the annotation
      // class (interface).
      // So, if the type qualifier annotation has specified a default When
      // value,
      // it will appear as an abstract method called "when".
      XMethod whenMethod = xclass.findMethod("when", "()Ljavax/annotation/meta/When;", false);
      if (whenMethod == null) {
        isStrict = true;
      }
      for (XMethod xmethod : xclass.getXMethods()) {
        if (xmethod.getName().equals("value") && xmethod.getSignature().startsWith("()")) {
          isExhaustive = xmethod.getAnnotation(EXHAUSTIVE_ANNOTATION) != null;
          if (isExhaustive) {
            // exhaustive qualifiers are automatically exclusive
            isExclusive = true;
          } else {
            // see if there is an explicit @Exclusive annotation
            isExclusive = xmethod.getAnnotation(EXCLUSIVE_ANNOTATION) != null;
          }

          break;
        }
      }
    } catch (MissingClassException e) {
      AnalysisContext.currentAnalysisContext()
          .getLookupFailureCallback()
          .reportMissingClass(e.getClassNotFoundException());
    } catch (CheckedAnalysisException e) {
      AnalysisContext.logError(
          "Error looking up annotation class " + typeQualifier.toDottedClassName(), e);
    }
    this.isStrict = isStrict;
    this.isExclusive = isExclusive;
    this.isExhaustive = isExhaustive;
    ClassDescriptor checkerName =
        DescriptorFactory.createClassDescriptor(typeQualifier.getClassName() + "$Checker");
    try {
      Global.getAnalysisCache().getClassAnalysis(ClassData.class, checkerName);
      // found it.
      //            System.out.println(checkerName);
      SecurityManager m = System.getSecurityManager();
      if (m == null) System.setSecurityManager(new ValidationSecurityManager());
      Class<?> c = validatorLoader.loadClass(checkerName.getDottedClassName());
      if (TypeQualifierValidator.class.isAssignableFrom(c)) {
        Class<? extends TypeQualifierValidator> checkerClass =
            c.asSubclass(TypeQualifierValidator.class);
        validator = getValidator(checkerClass);
        qualifierClass = getQualifierClass(typeQualifier);

        InvocationHandler handler =
            new InvocationHandler() {

              public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
                if (arg1.getName() == "value") return TypeQualifierValue.this.value;
                throw new UnsupportedOperationException("Can't handle " + arg1);
              }
            };

        proxy =
            qualifierClass.cast(
                Proxy.newProxyInstance(validatorLoader, new Class[] {qualifierClass}, handler));
      }
    } catch (ClassNotFoundException e) {
      assert true; // ignore
    } catch (CheckedAnalysisException e) {
      assert true; // ignore
    } catch (Exception e) {
      AnalysisContext.logError("Unable to construct type qualifier checker " + checkerName, e);
    } catch (Throwable e) {
      AnalysisContext.logError(
          "Unable to construct type qualifier checker "
              + checkerName
              + " due to "
              + e.getClass().getSimpleName()
              + ":"
              + e.getMessage());
    }
    this.validator = validator;
    this.typeQualifierClass = qualifierClass;
    this.proxy = proxy;
  }