/**
   * implements the visitor to look for calls to java.utils.Properties.put, where the value is a non
   * String. Reports both cases, where if it is a string, at a lower lever.
   *
   * @param seen the currently parsed op code
   */
  @Override
  public void sawOpcode(int seen) {
    try {
      stack.precomputation(this);

      if (seen == INVOKEVIRTUAL) {
        String clsName = getClassConstantOperand();
        if ("java/util/Properties".equals(clsName)) {
          String methodName = getNameConstantOperand();
          if ("put".equals(methodName)) {
            String sig = getSigConstantOperand();
            if (SignatureBuilder.SIG_TWO_OBJECTS_TO_OBJECT.equals(sig)
                && (stack.getStackDepth() >= 3)) {
              OpcodeStack.Item valueItem = stack.getStackItem(0);
              String valueSig = valueItem.getSignature();
              if (Values.SIG_JAVA_LANG_STRING.equals(valueSig)) {
                bugReporter.reportBug(
                    new BugInstance(
                            this,
                            BugType.IPU_IMPROPER_PROPERTIES_USE_SETPROPERTY.name(),
                            LOW_PRIORITY)
                        .addClass(this)
                        .addMethod(this)
                        .addSourceLine(this));
              } else if (Values.SIG_JAVA_LANG_OBJECT.equals(valueSig)) {
                bugReporter.reportBug(
                    new BugInstance(
                            this,
                            BugType.IPU_IMPROPER_PROPERTIES_USE_SETPROPERTY.name(),
                            NORMAL_PRIORITY)
                        .addClass(this)
                        .addMethod(this)
                        .addSourceLine(this));
              } else {
                bugReporter.reportBug(
                    new BugInstance(
                            this, BugType.IPU_IMPROPER_PROPERTIES_USE.name(), NORMAL_PRIORITY)
                        .addClass(this)
                        .addMethod(this)
                        .addSourceLine(this));
              }
            }
          }
        }
      }
    } finally {
      stack.sawOpcode(this, seen);
    }
  }
  /**
   * implements the visitor to look for methods that return a constant
   *
   * @param seen the opcode of the currently parsed instruction
   */
  @Override
  public void sawOpcode(int seen) {
    boolean sawSBToString = false;
    try {
      if (!methodSuspect) {
        return;
      }

      stack.precomputation(this);
      if ((seen >= IRETURN) && (seen <= ARETURN)) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);

          int register = item.getRegisterNumber();
          if (registerConstants.containsKey(register)
              && (registerConstants.get(register) == null)) {
            methodSuspect = false;
            return;
          }

          Object constant = item.getConstant();
          if (constant == null) {
            methodSuspect = false;
            return;
          }
          if (Boolean.TRUE.equals(item.getUserValue()) && ("".equals(constant))) {
            methodSuspect = false;
            return;
          }
          if ((returnConstant != null) && (!returnConstant.equals(constant))) {
            methodSuspect = false;
            return;
          }

          returnRegister = item.getRegisterNumber();
          returnConstant = constant;
        }
      } else if ((seen == GOTO) || (seen == GOTO_W)) {
        if (stack.getStackDepth() > 0) {
          methodSuspect =
              false; // Trinaries confuse us too much, if the code has a ternary well - oh well
        }
      } else if (seen == INVOKEVIRTUAL) {
        String clsName = getClassConstantOperand();
        if (clsName.startsWith("java/lang/StringB")) {
          sawSBToString = "toString".equals(getNameConstantOperand());
        }
      } else if ((seen >= ISTORE) && (seen <= ASTORE_3) || (seen == IINC)) {
        int register = getRegisterOperand();
        if ((returnRegister != -1) && (register == returnRegister)) {
          methodSuspect = false;
        }

        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          Object constant = item.getConstant();
          if (registerConstants.containsKey(register)) {
            if ((constant == null) || !constant.equals(registerConstants.get(register))) {
              registerConstants.put(register, null);
            }
          } else {
            registerConstants.put(register, constant);
          }
        } else {
          registerConstants.put(register, null);
        }

        if (returnRegister == register) {
          Object constant = registerConstants.get(returnRegister);
          if (constant != null) {
            methodSuspect = false;
          }
        }
      }

    } finally {
      TernaryPatcher.pre(stack, seen);
      stack.sawOpcode(this, seen);
      TernaryPatcher.post(stack, seen);
      if (sawSBToString && (stack.getStackDepth() > 0)) {
        OpcodeStack.Item item = stack.getStackItem(0);
        item.setUserValue(Boolean.TRUE);
      }
    }
  }
  /**
   * overrides the visitor to look for uses of collections where the only access to to the
   * collection is to write to it
   *
   * @param seen the opcode of the currently visited instruction
   */
  @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
      value = "SF_SWITCH_FALLTHROUGH",
      justification = "This fall-through is deliberate and documented")
  @Override
  public void sawOpcode(int seen) {
    Object userObject = null;

    // saving and restoring the userobject of the top item, works around a
    // bug in Findbugs proper
    if (stack.getStackDepth() > 0) {
      userObject = stack.getStackItem(0).getUserValue();
    }
    stack.precomputation(this);
    if (stack.getStackDepth() > 0) {
      stack.getStackItem(0).setUserValue(userObject);
      userObject = null;
    }

    try {
      switch (seen) {
        case INVOKESPECIAL:
          userObject = sawInvokeSpecial(userObject);
          break;
        case INVOKEINTERFACE:
        case INVOKEVIRTUAL:
          sawInvokeInterfaceVirtual();
          break;
        case INVOKESTATIC:
          userObject = sawInvokeStatic(userObject);
          // $FALL-THROUGH$
        case INVOKEDYNAMIC:
          processMethodParms();
          break;
        case ARETURN:
          if (stack.getStackDepth() > 0) {
            OpcodeStack.Item item = stack.getStackItem(0);
            clearUserValue(item);
          }
          break;

        case ASTORE_0:
        case ASTORE_1:
        case ASTORE_2:
        case ASTORE_3:
        case ASTORE:
          sawAStore(seen);
          break;

        case ALOAD_0:
        case ALOAD_1:
        case ALOAD_2:
        case ALOAD_3:
        case ALOAD:
          userObject = sawLoad(seen, userObject);
          break;

        case AASTORE:
          if (stack.getStackDepth() >= 3) {
            OpcodeStack.Item item = stack.getStackItem(0);
            clearUserValue(item);
          }
          break;

        case PUTFIELD:
          sawPutField();
          break;

        case GETFIELD:
          userObject = sawGetField(userObject);
          break;

        case PUTSTATIC:
          sawPutStatic();
          break;

        case GETSTATIC:
          userObject = sawGetStatic(userObject);
          break;

        case GOTO:
        case IFNULL:
        case IFNONNULL:
          if (stack.getStackDepth() > 0) {
            OpcodeStack.Item item = stack.getStackItem(0);
            Object uo = item.getUserValue();
            if ((uo != null) && !(uo instanceof Boolean)) {
              clearUserValue(item);
            }
            sawTernary = true;
          }
          break;
        default:
          break;
      }
    } finally {
      TernaryPatcher.pre(stack, seen);
      stack.sawOpcode(this, seen);
      TernaryPatcher.post(stack, seen);
      if ((userObject != null) && (stack.getStackDepth() > 0)) {
        OpcodeStack.Item item = stack.getStackItem(0);
        item.setUserValue(userObject);
      }
      if (sawTernary) {
        handleTernary(seen);
      }
    }
  }
  /**
   * overrides the visitor to look for calls to static methods that are known to return immutable
   * collections It records those variables, and documents if what the method returns is one of
   * those objects.
   */
  @Override
  public void sawOpcode(int seen) {
    ImmutabilityType seenImmutable = null;
    try {
      stack.precomputation(this);

      switch (seen) {
        case INVOKESTATIC:
          {
            String className = getClassConstantOperand();
            String methodName = getNameConstantOperand();

            if (IMMUTABLE_PRODUCING_METHODS.contains(className + '.' + methodName)) {
              seenImmutable = ImmutabilityType.IMMUTABLE;
              break;
            }
          }
          // $FALL-THROUGH$
        case INVOKEINTERFACE:
        case INVOKESPECIAL:
        case INVOKEVIRTUAL:
          {
            String className = getClassConstantOperand();
            String methodName = getNameConstantOperand();
            String signature = getSigConstantOperand();

            MethodInfo mi =
                Statistics.getStatistics().getMethodStatistics(className, methodName, signature);
            seenImmutable = mi.getImmutabilityType();
            if (seenImmutable == ImmutabilityType.UNKNOWN) seenImmutable = null;
          }
          break;

        case ARETURN:
          {
            if (stack.getStackDepth() > 0) {
              OpcodeStack.Item item = stack.getStackItem(0);
              ImmutabilityType type = (ImmutabilityType) item.getUserValue();
              if (type == null) type = ImmutabilityType.UNKNOWN;

              switch (imType) {
                case UNKNOWN:
                  switch (type) {
                    case IMMUTABLE:
                      imType = ImmutabilityType.IMMUTABLE;
                      break;
                    case POSSIBLY_IMMUTABLE:
                      imType = ImmutabilityType.POSSIBLY_IMMUTABLE;
                      break;
                    default:
                      imType = ImmutabilityType.MUTABLE;
                      break;
                  }
                  break;

                case IMMUTABLE:
                  if (type != ImmutabilityType.IMMUTABLE) {
                    imType = ImmutabilityType.POSSIBLY_IMMUTABLE;
                  }
                  break;

                case POSSIBLY_IMMUTABLE:
                  break;

                case MUTABLE:
                  if (type == ImmutabilityType.IMMUTABLE) {
                    imType = ImmutabilityType.POSSIBLY_IMMUTABLE;
                  }
                  break;
              }
            }
            break;
          }
        default:
          break;
      }

    } finally {
      stack.sawOpcode(this, seen);
      if (seenImmutable != null) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          item.setUserValue(seenImmutable);
        }
      }
    }
  }
Пример #5
0
  @Override
  public void sawOpcode(int seen) {
    try {
      stack.precomputation(this);

      int pc = getPC();
      if ((loopEnd != -1) && (pc > loopEnd)) {
        loopStart = -1;
        loopEnd = -1;
        regValueType.clear();
      }

      if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
        int reg = RegisterUtils.getALoadReg(this, seen);
        State type = regValueType.get(Integer.valueOf(reg));
        if (type != null) state = type;
        else state = State.SEEN_NOTHING;
        return;
      }
      if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          int reg = RegisterUtils.getAStoreReg(this, seen);
          regValueType.put(Integer.valueOf(reg), (State) item.getUserValue());
        }
        state = State.SEEN_NOTHING;
        return;
      }
      if ((seen == ILOAD) || ((seen >= ILOAD_0) && (seen <= ILOAD_3))) {
        int reg = RegisterUtils.getLoadReg(this, seen);
        State type = regValueType.get(Integer.valueOf(reg));
        if (type != null) state = type;
        else state = State.SEEN_NOTHING;
        return;
      }
      if ((seen == ISTORE) || ((seen >= ISTORE_0) && (seen <= ISTORE_3))) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          int reg = RegisterUtils.getStoreReg(this, seen);
          regValueType.put(Integer.valueOf(reg), (State) item.getUserValue());
        }
        state = State.SEEN_NOTHING;
        return;
      }

      switch (state) {
        case SEEN_NOTHING:
          if (seen == INVOKESPECIAL) {
            if (("java/util/StringTokenizer".equals(getClassConstantOperand()))
                && (Values.CONSTRUCTOR.equals(getNameConstantOperand()))
                && ("(Ljava/lang/String;Ljava/lang/String;)V".equals(getSigConstantOperand())))
              state = State.SEEN_STRINGTOKENIZER;
          }
          break;

        case SEEN_STRINGTOKENIZER:
          if (seen == INVOKEVIRTUAL) {
            String methodName = getNameConstantOperand();
            String signature = getSigConstantOperand();
            if (("countTokens".equals(methodName)) && ("()I".equals(signature)))
              state = State.SEEN_COUNTTOKENS;
            else if ("hasMoreTokens".equals(methodName) || "hasMoreElements".equals(methodName))
              state = State.SEEN_HASMORE;
            else if ("nextToken".equals(methodName) || "nextElement".equals(methodName)) {
              if ((pc < loopStart) || (pc > loopEnd)) regValueType.clear();
              else state = State.SEEN_NEXT;
            }
          }
          break;

        case SEEN_COUNTTOKENS:
          if (seen == ANEWARRAY) state = State.SEEN_NEWARRAY;
          else if (seen == IF_ICMPGE) {
            int target = getBranchTarget() - 3; // sizeof goto
            byte[] code = getCode().getCode();
            if ((code[target] & 0x000000FF) == GOTO) {
              int offset = (code[target + 1] << 1) + code[target + 2];
              int gotoTarget = target + offset + 3;
              if (gotoTarget < getPC()) {
                loopStart = gotoTarget;
                loopEnd = target;
              }
            }
          }
          break;

        case SEEN_HASMORE:
          if (seen == IFEQ) {
            int target = getBranchTarget() - 3; // sizeof goto
            byte[] code = getCode().getCode();
            if ((code[target] & 0x000000FF) == GOTO) {
              int offset = (code[target + 1] << 1) + code[target + 2];
              int gotoTarget = target + offset + 3;
              if (gotoTarget < getPC()) {
                loopStart = gotoTarget;
                loopEnd = target;
              }
            }
          }
          state = State.SEEN_NOTHING;
          break;

        case SEEN_NEXT:
          if (seen == AASTORE) {
            if ((pc > loopStart) && (pc < loopEnd)) {
              if (stack.getStackDepth() > 2) {
                OpcodeStack.Item arrayItem = stack.getStackItem(2);
                State arrayType = (State) arrayItem.getUserValue();
                OpcodeStack.Item elemItem = stack.getStackItem(0);
                State elemType = (State) elemItem.getUserValue();
                if ((arrayType == State.SEEN_NEWARRAY) && (elemType == State.SEEN_NEXT)) {
                  bugReporter.reportBug(
                      new BugInstance(this, BugType.USS_USE_STRING_SPLIT.name(), NORMAL_PRIORITY)
                          .addClass(this)
                          .addMethod(this)
                          .addSourceLine(this));
                }
              }
            }
          }
          state = State.SEEN_NOTHING;
          break;

        case SEEN_ARRAYSTORE:
        case SEEN_NEWARRAY:
          break;
      }
    } finally {
      TernaryPatcher.pre(stack, seen);
      stack.sawOpcode(this, seen);
      TernaryPatcher.post(stack, seen);
      if (state != State.SEEN_NOTHING) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          item.setUserValue(state);
        }
      }
    }
  }