/** * implements the visitor to reset the stack * * @param obj the context object of the currently parsed code block */ @Override public void visitCode(Code obj) { stack.resetForMethodEntry(this); super.visitCode(obj); for (Map.Entry<Integer, CollectionRegInfo> entry : syncRegs.entrySet()) { CollectionRegInfo cri = entry.getValue(); if (!cri.getIgnore()) { bugReporter.reportBug( new BugInstance(this, "LSYC_LOCAL_SYNCHRONIZED_COLLECTION", cri.getPriority()) .addClass(this) .addMethod(this) .addSourceLine(cri.getSourceLineAnnotation())); } } }
/** * 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); } } } }