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