/** * 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); } } } }
@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); } } } }