Package com.mebigfatguy.fbcontrib.detect
Class DeletingWhileIterating
- java.lang.Object
-
- edu.umd.cs.findbugs.visitclass.BetterVisitor
-
- edu.umd.cs.findbugs.visitclass.PreorderVisitor
-
- edu.umd.cs.findbugs.visitclass.AnnotationVisitor
-
- edu.umd.cs.findbugs.visitclass.DismantleBytecode
-
- edu.umd.cs.findbugs.BytecodeScanningDetector
-
- com.mebigfatguy.fbcontrib.detect.AbstractCollectionScanningDetector
-
- com.mebigfatguy.fbcontrib.detect.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 com.mebigfatguy.fbcontrib.detect.AbstractCollectionScanningDetector
bugReporter, collectionClass, stack
-
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
-
-
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 popprivate 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 loopprivate boolean
isCollection(java.lang.String className)
returns whether the class name is derived from java.util.Collectionprivate 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 iteratedvoid
visitClassContext(edu.umd.cs.findbugs.ba.ClassContext classContext)
implements the visitor to setup the opcode stack, collectionGroups, groupToIterator and loopsvoid
visitCode(org.apache.bcel.classfile.Code obj)
implements the visitor to reset the stack, collectionGroups, groupToIterator and loops-
Methods inherited from class com.mebigfatguy.fbcontrib.detect.AbstractCollectionScanningDetector
isLocalCollection
-
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
-
-
-
-
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
-
collectionGroups
private java.util.List<DeletingWhileIterating.GroupPair> collectionGroups
-
groupToIterator
private java.util.Map<java.lang.Integer,java.lang.Integer> groupToIterator
-
loops
private java.util.Map<java.lang.Integer,DeletingWhileIterating.Loop> loops
-
endOfScopes
private java.util.Map<java.lang.Integer,java.util.BitSet> endOfScopes
-
-
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 interfaceedu.umd.cs.findbugs.Detector
- Overrides:
visitClassContext
in classAbstractCollectionScanningDetector
- 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 interfaceorg.apache.bcel.classfile.Visitor
- Overrides:
visitCode
in classAbstractCollectionScanningDetector
- 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 classedu.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 checkingneedsPop
- 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)
-
-