/**
   * 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);
      }
    }
  }
  /**
   * implements the visitor to find stores to locals of synchronized collections
   *
   * @param seen the opcode of the currently parsed instruction
   */
  @Override
  public void sawOpcode(int seen) {
    Integer tosIsSyncColReg = null;
    try {
      stack.mergeJumps(this);

      if (seen == INVOKESPECIAL) {
        if ("<init>".equals(getNameConstantOperand())) {
          Integer minVersion = syncCtors.get(getClassConstantOperand());
          if ((minVersion != null) && (classVersion >= minVersion.intValue())) {
            tosIsSyncColReg = Integer.valueOf(-1);
          }
        }
      } else if (seen == INVOKESTATIC) {
        if ("java/util/Collections".equals(getClassConstantOperand())) {
          if (syncMethods.contains(getNameConstantOperand())) {
            tosIsSyncColReg = Integer.valueOf(-1);
          }
        }
      } else 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);
          if (item.getUserValue() != null) {
            if (!syncRegs.containsKey(Integer.valueOf(reg))) {
              CollectionRegInfo cri =
                  new CollectionRegInfo(
                      SourceLineAnnotation.fromVisitedInstruction(this),
                      RegisterUtils.getLocalVariableEndRange(
                          getMethod().getLocalVariableTable(), reg, getNextPC()));
              syncRegs.put(Integer.valueOf(reg), cri);
            }
          } else {
            CollectionRegInfo cri = syncRegs.get(Integer.valueOf(reg));
            if (cri == null) {
              cri =
                  new CollectionRegInfo(
                      RegisterUtils.getLocalVariableEndRange(
                          getMethod().getLocalVariableTable(), reg, getNextPC()));
              syncRegs.put(Integer.valueOf(reg), cri);
            }
            cri.setIgnore();
          }
        }
      } else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
        int reg = RegisterUtils.getALoadReg(this, seen);
        CollectionRegInfo cri = syncRegs.get(Integer.valueOf(reg));
        if ((cri != null) && !cri.getIgnore()) tosIsSyncColReg = Integer.valueOf(reg);
      } else if ((seen == PUTFIELD) || (seen == ARETURN)) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          syncRegs.remove(item.getUserValue());
        }
      }

      if (syncRegs.size() > 0) {
        if ((seen == INVOKESPECIAL)
            || (seen == INVOKEINTERFACE)
            || (seen == INVOKEVIRTUAL)
            || (seen == INVOKESTATIC)) {
          String sig = getSigConstantOperand();
          int argCount = Type.getArgumentTypes(sig).length;
          if (stack.getStackDepth() >= argCount) {
            for (int i = 0; i < argCount; i++) {
              OpcodeStack.Item item = stack.getStackItem(i);
              CollectionRegInfo cri = syncRegs.get(item.getUserValue());
              if (cri != null) cri.setPriority(LOW_PRIORITY);
            }
          }
        } else if (seen == MONITORENTER) {
          // Assume if synchronized blocks are used then something tricky is going on.
          // There is really no valid reason for this, other than folks who use
          // synchronized blocks tend to know what's going on.
          if (stack.getStackDepth() > 0) {
            OpcodeStack.Item item = stack.getStackItem(0);
            syncRegs.remove(item.getUserValue());
          }
        } else if (seen == AASTORE) {
          if (stack.getStackDepth() > 0) {
            OpcodeStack.Item item = stack.getStackItem(0);
            syncRegs.remove(item.getUserValue());
          }
        }
      }

      int curPC = getPC();
      Iterator<CollectionRegInfo> it = syncRegs.values().iterator();
      while (it.hasNext()) {
        CollectionRegInfo cri = it.next();
        if (cri.getEndPCRange() < curPC) {
          if (!cri.getIgnore()) {
            bugReporter.reportBug(
                new BugInstance(this, "LSYC_LOCAL_SYNCHRONIZED_COLLECTION", cri.getPriority())
                    .addClass(this)
                    .addMethod(this)
                    .addSourceLine(cri.getSourceLineAnnotation()));
          }
          it.remove();
        }
      }
    } finally {
      TernaryPatcher.pre(stack, seen);
      stack.sawOpcode(this, seen);
      TernaryPatcher.post(stack, seen);
      if (tosIsSyncColReg != null) {
        if (stack.getStackDepth() > 0) {
          OpcodeStack.Item item = stack.getStackItem(0);
          item.setUserValue(tosIsSyncColReg);
        }
      }
    }
  }
  /**
   * 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);
      }
    }
  }
Example #4
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);
        }
      }
    }
  }