Class DeletingWhileIterating

  • All Implemented Interfaces:
    edu.umd.cs.findbugs.Detector, edu.umd.cs.findbugs.Priorities, edu.umd.cs.findbugs.visitclass.Constants2, org.apache.bcel.classfile.Visitor, org.apache.bcel.Constants

    @CustomUserValue
    public class DeletingWhileIterating
    extends AbstractCollectionScanningDetector
    looks for deletion of items from a collection using the remove method of the collection at the same time that the collection is being iterated on. If this occurs the iterator will become invalid and throw a ConcurrentModificationException. Instead, the remove should be called on the iterator itself.
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      (package private) static class  DeletingWhileIterating.GroupPair
      represents aliases of some kind to some sort of a collection, or a related object like a keySet, or an iterator
      (package private) static class  DeletingWhileIterating.Loop
      represents a simple loop
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private java.util.List<DeletingWhileIterating.GroupPair> collectionGroups  
      private static java.util.Set<QMethod> collectionMethods  
      private java.util.Map<java.lang.Integer,​java.util.BitSet> endOfScopes  
      private static java.util.Set<org.apache.bcel.classfile.JavaClass> exceptionClasses  
      private java.util.Map<java.lang.Integer,​java.lang.Integer> groupToIterator  
      private static QMethod HASNEXT  
      private static QMethod ITERATOR  
      private static org.apache.bcel.classfile.JavaClass iteratorClass  
      private java.util.Map<java.lang.Integer,​DeletingWhileIterating.Loop> loops  
      private static java.util.Map<QMethod,​java.lang.Integer> modifyingMethods  
      private static QMethod REMOVE  
      • Fields inherited from class edu.umd.cs.findbugs.visitclass.DismantleBytecode

        codeBytes, lineNumberTable, M_BR, M_CP, M_INT, M_PAD, M_R, M_UINT
      • Fields inherited from interface org.apache.bcel.Constants

        AALOAD, AASTORE, ACC_ABSTRACT, ACC_ANNOTATION, ACC_BRIDGE, ACC_ENUM, ACC_FINAL, ACC_INTERFACE, ACC_NATIVE, ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC, ACC_STATIC, ACC_STRICT, ACC_SUPER, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_SYPER, ACC_TRANSIENT, ACC_VARARGS, ACC_VOLATILE, ACCESS_NAMES, ACONST_NULL, ALOAD, ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3, ANEWARRAY, ANEWARRAY_QUICK, APPEND_FRAME, APPEND_FRAME_MAX, ARETURN, ARRAYLENGTH, ASTORE, ASTORE_0, ASTORE_1, ASTORE_2, ASTORE_3, ATHROW, ATTR_ANNOTATION_DEFAULT, ATTR_CODE, ATTR_CONSTANT_VALUE, ATTR_DEPRECATED, ATTR_ENCLOSING_METHOD, ATTR_EXCEPTIONS, ATTR_INNER_CLASSES, ATTR_LINE_NUMBER_TABLE, ATTR_LOCAL_VARIABLE_TABLE, ATTR_LOCAL_VARIABLE_TYPE_TABLE, ATTR_PMG, ATTR_RUNTIME_VISIBLE_ANNOTATIONS, ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, ATTR_RUNTIMEIN_VISIBLE_ANNOTATIONS, ATTR_RUNTIMEIN_VISIBLE_PARAMETER_ANNOTATIONS, ATTR_SIGNATURE, ATTR_SOURCE_FILE, ATTR_STACK_MAP, ATTR_STACK_MAP_TABLE, ATTR_SYNTHETIC, ATTR_UNKNOWN, ATTRIBUTE_NAMES, BALOAD, BASTORE, BIPUSH, BREAKPOINT, CALOAD, CASTORE, CHECKCAST, CHECKCAST_QUICK, CHOP_FRAME, CHOP_FRAME_MAX, CLASS_TYPE_NAMES, CONSTANT_Class, CONSTANT_Double, CONSTANT_Fieldref, CONSTANT_Float, CONSTANT_Integer, CONSTANT_InterfaceMethodref, CONSTANT_InvokeDynamic, CONSTANT_Long, CONSTANT_MethodHandle, CONSTANT_Methodref, CONSTANT_MethodType, CONSTANT_NameAndType, CONSTANT_NAMES, CONSTANT_String, CONSTANT_Utf8, CONSTRUCTOR_NAME, CONSUME_STACK, D2F, D2I, D2L, DADD, DALOAD, DASTORE, DCMPG, DCMPL, DCONST_0, DCONST_1, DDIV, DLOAD, DLOAD_0, DLOAD_1, DLOAD_2, DLOAD_3, DMUL, DNEG, DREM, DRETURN, DSTORE, DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3, DSUB, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, F2D, F2I, F2L, FADD, FALOAD, FASTORE, FCMPG, FCMPL, FCONST_0, FCONST_1, FCONST_2, FDIV, FLOAD, FLOAD_0, FLOAD_1, FLOAD_2, FLOAD_3, FMUL, FNEG, FREM, FRETURN, FSTORE, FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3, FSUB, FULL_FRAME, GETFIELD, GETFIELD_QUICK, GETFIELD_QUICK_W, GETFIELD2_QUICK, GETSTATIC, GETSTATIC_QUICK, GETSTATIC2_QUICK, GOTO, GOTO_W, I2B, I2C, I2D, I2F, I2L, I2S, IADD, IALOAD, IAND, IASTORE, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, ICONST_M1, IDIV, IF_ACMPEQ, IF_ACMPNE, IF_ICMPEQ, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ICMPLT, IF_ICMPNE, IFEQ, IFGE, IFGT, IFLE, IFLT, IFNE, IFNONNULL, IFNULL, IINC, ILLEGAL_OPCODE, ILLEGAL_TYPE, ILOAD, ILOAD_0, ILOAD_1, ILOAD_2, ILOAD_3, IMPDEP1, IMPDEP2, IMUL, INEG, INSTANCEOF, INSTANCEOF_QUICK, INT2BYTE, INT2CHAR, INT2SHORT, INTERFACES_IMPLEMENTED_BY_ARRAYS, INVOKEDYNAMIC, INVOKEINTERFACE, INVOKEINTERFACE_QUICK, INVOKENONVIRTUAL, INVOKENONVIRTUAL_QUICK, INVOKESPECIAL, INVOKESTATIC, INVOKESTATIC_QUICK, INVOKESUPER_QUICK, INVOKEVIRTUAL, INVOKEVIRTUAL_QUICK, INVOKEVIRTUAL_QUICK_W, INVOKEVIRTUALOBJECT_QUICK, IOR, IREM, IRETURN, ISHL, ISHR, ISTORE, ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3, ISUB, ITEM_Bogus, ITEM_Double, ITEM_Float, ITEM_InitObject, ITEM_Integer, ITEM_Long, ITEM_NAMES, ITEM_NewObject, ITEM_Null, ITEM_Object, IUSHR, IXOR, JSR, JSR_W, KNOWN_ATTRIBUTES, L2D, L2F, L2I, LADD, LALOAD, LAND, LASTORE, LCMP, LCONST_0, LCONST_1, LDC, LDC_QUICK, LDC_W, LDC_W_QUICK, LDC2_W, LDC2_W_QUICK, LDIV, LLOAD, LLOAD_0, LLOAD_1, LLOAD_2, LLOAD_3, LMUL, LNEG, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR, LSTORE, LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3, LSUB, LUSHR, LXOR, MAJOR, MAJOR_1_1, MAJOR_1_2, MAJOR_1_3, MAJOR_1_4, MAJOR_1_5, MAJOR_1_6, MAJOR_1_7, MAJOR_1_8, MAX_ACC_FLAG, MAX_BYTE, MAX_CODE_SIZE, MAX_CP_ENTRIES, MAX_SHORT, MINOR, MINOR_1_1, MINOR_1_2, MINOR_1_3, MINOR_1_4, MINOR_1_5, MINOR_1_6, MINOR_1_7, MINOR_1_8, MONITORENTER, MONITOREXIT, MULTIANEWARRAY, MULTIANEWARRAY_QUICK, NEW, NEW_QUICK, NEWARRAY, NO_OF_OPERANDS, NOP, OPCODE_NAMES, POP, POP2, PRODUCE_STACK, PUSH, PUTFIELD, PUTFIELD_QUICK, PUTFIELD_QUICK_W, PUTFIELD2_QUICK, PUTSTATIC, PUTSTATIC_QUICK, PUTSTATIC2_QUICK, RESERVED, RET, RETURN, SALOAD, SAME_FRAME, SAME_FRAME_EXTENDED, SAME_FRAME_MAX, SAME_LOCALS_1_STACK_ITEM_FRAME, SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED, SAME_LOCALS_1_STACK_ITEM_FRAME_MAX, SASTORE, SHORT_TYPE_NAMES, SIPUSH, STATIC_INITIALIZER_NAME, SWAP, SWITCH, T_ADDRESS, T_ARRAY, T_BOOLEAN, T_BYTE, T_CHAR, T_DOUBLE, T_FLOAT, T_INT, T_LONG, T_OBJECT, T_REFERENCE, T_SHORT, T_UNKNOWN, T_VOID, TABLESWITCH, TYPE_NAMES, TYPE_OF_OPERANDS, UNDEFINED, UNPREDICTABLE, WIDE
      • Fields inherited from interface edu.umd.cs.findbugs.Priorities

        EXP_PRIORITY, HIGH_PRIORITY, IGNORE_PRIORITY, LOW_PRIORITY, NORMAL_PRIORITY
    • Constructor Summary

      Constructors 
      Constructor Description
      DeletingWhileIterating​(edu.umd.cs.findbugs.BugReporter bugReporter)
      constructs a DWI detector given the reporter to report bugs on
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private boolean breakFollows​(DeletingWhileIterating.Loop loop, boolean needsPop)
      looks to see if the following instruction is a GOTO, preceded by potentially a pop
      private void buildVariableEndScopeMap()  
      private int findCollectionGroup​(edu.umd.cs.findbugs.OpcodeStack.Item itm, boolean addIfNotFound)  
      private static java.lang.Comparable<?> getGroupElement​(edu.umd.cs.findbugs.OpcodeStack.Item itm)
      given an register or field, look to see if this thing is associated with an already discovered loop
      private boolean isCollection​(java.lang.String className)
      returns whether the class name is derived from java.util.Collection
      private void processEndOfScopes​(java.lang.Integer pc)  
      private void removeFromCollectionGroup​(edu.umd.cs.findbugs.OpcodeStack.Item itm)  
      private boolean returnFollows​(boolean couldSeePop)
      This attempts to see if there is some form of a return statement following the collection modifying statement in the loop.
      void sawOpcode​(int seen)
      implements the visitor to look for deletes on collections that are being iterated
      void visitClassContext​(edu.umd.cs.findbugs.ba.ClassContext classContext)
      implements the visitor to setup the opcode stack, collectionGroups, groupToIterator and loops
      void visitCode​(org.apache.bcel.classfile.Code obj)
      implements the visitor to reset the stack, collectionGroups, groupToIterator and loops
      • Methods inherited from class edu.umd.cs.findbugs.BytecodeScanningDetector

        getClassContext, report, shouldVisitCode
      • Methods inherited from class edu.umd.cs.findbugs.visitclass.DismantleBytecode

        afterOpcode, areOppositeBranches, atCatchBlock, beforeOpcode, getBranchFallThrough, getBranchOffset, getBranchTarget, getClassConstantOperand, getClassDescriptorOperand, getCodeByte, getConstantRefOperand, getDefaultSwitchOffset, getDottedClassConstantOperand, getFieldDescriptorOperand, getIntConstant, getLongConstant, getMaxPC, getMethodDescriptorOperand, getNameConstantOperand, getNextCodeByte, getNextOpcode, getNextPC, getOpcode, getPC, getPrevOpcode, getRefConstantOperand, getRefFieldIsStatic, getRegisterOperand, getSigConstantOperand, getStringConstantOperand, getSwitchLabels, getSwitchOffsets, getXClassOperand, getXFieldOperand, getXMethodOperand, isBranch, isMethodCall, isRegisterLoad, isRegisterStore, isRegisterStore, isReturn, isShift, isSwitch, isWideOpcode, printOpCode, sawBranchTo, sawClass, sawDouble, sawField, sawFloat, sawIMethod, sawInt, sawLong, sawMethod, sawRegister, sawString, visit
      • Methods inherited from class edu.umd.cs.findbugs.visitclass.AnnotationVisitor

        getAnnotationParameterAsString, getAnnotationParameterAsStringArray, visitAnnotation, visitAnnotation, visitParameterAnnotation, visitParameterAnnotation, visitSyntheticParameterAnnotation
      • Methods inherited from class edu.umd.cs.findbugs.visitclass.PreorderVisitor

        amVisitingMainMethod, asUnsignedByte, doVisitMethod, getClassDescriptor, getClassName, getCode, getConstantPool, getDottedClassName, getDottedFieldSig, getDottedMethodSig, getDottedSuperclassName, getField, getFieldDescriptor, getFieldIsStatic, getFieldName, getFieldSig, getFullyQualifiedFieldName, getFullyQualifiedMethodName, getMethod, getMethodDescriptor, getMethodName, getMethodSig, getMethodVisitOrder, getNumberArguments, getNumberMethodArguments, getPackageName, getSizeOfSurroundingTryBlock, getSizeOfSurroundingTryBlock, getSourceFile, getStringFromIndex, getSuperclassName, getSurroundingCaughtExceptions, getSurroundingCaughtExceptions, getSurroundingTryBlock, getSurroundingTryBlock, getThisClass, getXClass, getXField, getXMethod, hasInterestingClass, hasInterestingMethod, isVisitMethodsInCallOrder, setupVisitorForClass, setVisitMethodsInCallOrder, shouldVisit, toString, visitAfter, visitAfter, visitAnnotationDefault, visitAnnotationEntry, visitConstantPool, visitEnclosingMethod, visitingField, visitingMethod, visitInnerClasses, visitJavaClass, visitLineNumberTable, visitLocalVariableTable, visitStackMapTable, visitStackMapTableEntry
      • Methods inherited from class edu.umd.cs.findbugs.visitclass.BetterVisitor

        clone, report, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visitCodeException, visitConstantClass, visitConstantDouble, visitConstantFieldref, visitConstantFloat, visitConstantInteger, visitConstantInterfaceMethodref, visitConstantLong, visitConstantMethodref, visitConstantNameAndType, visitConstantString, visitConstantUtf8, visitConstantValue, visitDeprecated, visitExceptionTable, visitField, visitInnerClass, visitLineNumber, visitLocalVariable, visitLocalVariableTypeTable, visitMethod, visitSignature, visitSourceFile, visitStackMap, visitStackMapEntry, visitSynthetic, visitUnknown
      • Methods inherited from class java.lang.Object

        equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
    • Field Detail

      • iteratorClass

        private static org.apache.bcel.classfile.JavaClass iteratorClass
      • exceptionClasses

        private static java.util.Set<org.apache.bcel.classfile.JavaClass> exceptionClasses
      • collectionMethods

        private static final java.util.Set<QMethod> collectionMethods
      • modifyingMethods

        private static final java.util.Map<QMethod,​java.lang.Integer> modifyingMethods
      • ITERATOR

        private static final QMethod ITERATOR
      • REMOVE

        private static final QMethod REMOVE
      • HASNEXT

        private static final QMethod HASNEXT
      • groupToIterator

        private java.util.Map<java.lang.Integer,​java.lang.Integer> groupToIterator
      • endOfScopes

        private java.util.Map<java.lang.Integer,​java.util.BitSet> endOfScopes
    • Constructor Detail

      • DeletingWhileIterating

        public DeletingWhileIterating​(edu.umd.cs.findbugs.BugReporter bugReporter)
        constructs a DWI detector given the reporter to report bugs on
        Parameters:
        bugReporter - the sync of bug reports
    • Method Detail

      • visitClassContext

        public void visitClassContext​(edu.umd.cs.findbugs.ba.ClassContext classContext)
        implements the visitor to setup the opcode stack, collectionGroups, groupToIterator and loops
        Specified by:
        visitClassContext in interface edu.umd.cs.findbugs.Detector
        Overrides:
        visitClassContext in class AbstractCollectionScanningDetector
        Parameters:
        classContext - the context object of the currently parsed class
      • visitCode

        public void visitCode​(org.apache.bcel.classfile.Code obj)
        implements the visitor to reset the stack, collectionGroups, groupToIterator and loops
        Specified by:
        visitCode in interface org.apache.bcel.classfile.Visitor
        Overrides:
        visitCode in class AbstractCollectionScanningDetector
        Parameters:
        obj - the context object of the currently parsed code block
      • sawOpcode

        public void sawOpcode​(int seen)
        implements the visitor to look for deletes on collections that are being iterated
        Overrides:
        sawOpcode in class edu.umd.cs.findbugs.visitclass.DismantleBytecode
        Parameters:
        seen - the opcode of the currently parsed instruction
      • breakFollows

        private boolean breakFollows​(DeletingWhileIterating.Loop loop,
                                     boolean needsPop)
        looks to see if the following instruction is a GOTO, preceded by potentially a pop
        Parameters:
        loop - the loop structure we are checking
        needsPop - whether we expect to see a pop next
        Returns:
        whether a GOTO is found
      • returnFollows

        private boolean returnFollows​(boolean couldSeePop)
        This attempts to see if there is some form of a return statement following the collection modifying statement in the loop. It is a bad cheat, because, we may allow a POP, or an ALOAD/ILOAD etc before the return. this is sloppy tho as it might be a multibyte instruction. It also might be a complex piece of code to load the return, or the method may not allow returns. But hopefully it's better than it was.
        Parameters:
        couldSeePop - if the preceding instruction returns a value, and thus might need to be popped
        Returns:
        when a following instruction issues some sort of return
      • isCollection

        private boolean isCollection​(@SlashedClassName
                                     java.lang.String className)
        returns whether the class name is derived from java.util.Collection
        Parameters:
        className - the class to check
        Returns:
        whether the class is a collection
      • getGroupElement

        private static java.lang.Comparable<?> getGroupElement​(edu.umd.cs.findbugs.OpcodeStack.Item itm)
        given an register or field, look to see if this thing is associated with an already discovered loop
        Parameters:
        itm - the item containing the register or field
        Returns:
        the group element
      • findCollectionGroup

        private int findCollectionGroup​(edu.umd.cs.findbugs.OpcodeStack.Item itm,
                                        boolean addIfNotFound)
      • removeFromCollectionGroup

        private void removeFromCollectionGroup​(edu.umd.cs.findbugs.OpcodeStack.Item itm)
      • buildVariableEndScopeMap

        private void buildVariableEndScopeMap()
      • processEndOfScopes

        private void processEndOfScopes​(java.lang.Integer pc)