Search in sources :

Example 1 with QMethod

use of com.mebigfatguy.fbcontrib.utils.QMethod in project fb-contrib by mebigfatguy.

the class DeletingWhileIterating method sawOpcode.

/**
 * implements the visitor to look for deletes on collections that are being iterated
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@Override
public void sawOpcode(int seen) {
    int groupId = -1;
    try {
        stack.precomputation(this);
        if (seen == Const.INVOKEINTERFACE) {
            String className = getClassConstantOperand();
            String methodName = getNameConstantOperand();
            String signature = getSigConstantOperand();
            QMethod methodInfo = new QMethod(methodName, signature);
            if (isCollection(className)) {
                if (collectionMethods.contains(methodInfo) || ITERATOR.equals(methodInfo)) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        groupId = findCollectionGroup(itm, true);
                    }
                } else if (REMOVE.equals(methodInfo)) {
                    if (stack.getStackDepth() > 1) {
                        OpcodeStack.Item itm = stack.getStackItem(1);
                        int id = findCollectionGroup(itm, true);
                        if ((id >= 0) && collectionGroups.get(id).isStandardCollection()) {
                            Integer it = groupToIterator.get(Integer.valueOf(id));
                            Loop loop = loops.get(it);
                            if (loop != null) {
                                int pc = getPC();
                                if (loop.hasPC(pc)) {
                                    boolean needPop = !Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(signature));
                                    if (!breakFollows(loop, needPop) && !returnFollows(needPop)) {
                                        bugReporter.reportBug(new BugInstance(this, BugType.DWI_DELETING_WHILE_ITERATING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                    }
                                }
                            }
                        }
                    }
                } else {
                    Integer numArgs = modifyingMethods.get(methodInfo);
                    if ((numArgs != null) && (stack.getStackDepth() > numArgs.intValue())) {
                        OpcodeStack.Item itm = stack.getStackItem(numArgs.intValue());
                        int id = findCollectionGroup(itm, true);
                        if (id >= 0) {
                            Integer it = groupToIterator.get(Integer.valueOf(id));
                            if (it != null) {
                                Loop loop = loops.get(it);
                                if (loop != null) {
                                    int pc = getPC();
                                    if (loop.hasPC(pc)) {
                                        boolean needPop = !Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(signature));
                                        boolean breakFollows = breakFollows(loop, needPop);
                                        boolean returnFollows = !breakFollows && returnFollows(needPop);
                                        if (!breakFollows && !returnFollows) {
                                            bugReporter.reportBug(new BugInstance(this, BugType.DWI_MODIFYING_WHILE_ITERATING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } else if ("java/util/Iterator".equals(className) && HASNEXT.equals(methodInfo) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                Integer id = (Integer) itm.getUserValue();
                if (id != null) {
                    groupId = id.intValue();
                }
            }
        } else if ((seen == Const.PUTFIELD) || (seen == Const.PUTSTATIC)) {
            if (stack.getStackDepth() > 1) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                Integer id = (Integer) itm.getUserValue();
                if (id == null) {
                    FieldAnnotation fa = FieldAnnotation.fromFieldDescriptor(new FieldDescriptor(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand(), false));
                    itm = new OpcodeStack.Item(itm.getSignature(), fa, stack.getStackItem(1).getRegisterNumber());
                    removeFromCollectionGroup(itm);
                    groupId = findCollectionGroup(itm, true);
                }
            }
        } else if (OpcodeUtils.isAStore(seen)) {
            if (stack.getStackDepth() > 0) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                Integer id = (Integer) itm.getUserValue();
                if (id != null) {
                    int reg = RegisterUtils.getAStoreReg(this, seen);
                    try {
                        JavaClass cls = itm.getJavaClass();
                        if ((cls != null) && cls.implementationOf(iteratorClass)) {
                            Integer regIt = Integer.valueOf(reg);
                            Iterator<Integer> curIt = groupToIterator.values().iterator();
                            while (curIt.hasNext()) {
                                if (curIt.next().equals(regIt)) {
                                    curIt.remove();
                                }
                            }
                            groupToIterator.put(id, regIt);
                        }
                        GroupPair pair = collectionGroups.get(id.intValue());
                        if (pair != null) {
                            pair.addMember(Integer.valueOf(reg));
                        }
                    } catch (ClassNotFoundException cnfe) {
                        bugReporter.reportMissingClass(cnfe);
                    }
                } else {
                    String cls = itm.getSignature();
                    if ((cls != null) && cls.startsWith(Values.SIG_QUALIFIED_CLASS_PREFIX)) {
                        cls = SignatureUtils.trimSignature(cls);
                        if (isCollection(cls) || "java/util/Iterator".equals(cls)) {
                            int reg = RegisterUtils.getAStoreReg(this, seen);
                            removeFromCollectionGroup(new OpcodeStack.Item(itm, reg));
                            Iterator<Integer> it = groupToIterator.values().iterator();
                            while (it.hasNext()) {
                                if (it.next().intValue() == reg) {
                                    it.remove();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        } else if (OpcodeUtils.isALoad(seen)) {
            int reg = RegisterUtils.getALoadReg(this, seen);
            OpcodeStack.Item itm = new OpcodeStack.Item(new OpcodeStack.Item(), reg);
            groupId = findCollectionGroup(itm, false);
        } else if ((seen == Const.IFEQ) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item itm = stack.getStackItem(0);
            Integer id = (Integer) itm.getUserValue();
            if (id != null) {
                int target = getBranchTarget();
                int gotoAddr = target - 3;
                int ins = getCode().getCode()[gotoAddr];
                if (ins < 0) {
                    ins = 256 + ins;
                }
                if ((ins == Const.GOTO) || (ins == Const.GOTO_W)) {
                    Integer reg = groupToIterator.get(id);
                    if (reg != null) {
                        loops.put(reg, new Loop(getPC(), gotoAddr));
                    }
                }
            }
        }
    } finally {
        TernaryPatcher.pre(stack, seen);
        stack.sawOpcode(this, seen);
        TernaryPatcher.post(stack, seen);
        if ((groupId >= 0) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item itm = stack.getStackItem(0);
            itm.setUserValue(Integer.valueOf(groupId));
        }
        processEndOfScopes(Integer.valueOf(getPC()));
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) BugInstance(edu.umd.cs.findbugs.BugInstance) ToString(com.mebigfatguy.fbcontrib.utils.ToString) FieldDescriptor(edu.umd.cs.findbugs.classfile.FieldDescriptor) QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) JavaClass(org.apache.bcel.classfile.JavaClass) FieldAnnotation(edu.umd.cs.findbugs.FieldAnnotation)

Example 2 with QMethod

use of com.mebigfatguy.fbcontrib.utils.QMethod in project fb-contrib by mebigfatguy.

the class DubiousListCollection method processInvokeInterface.

private void processInvokeInterface() {
    String className = this.getClassConstantOperand();
    if (className.startsWith("java/util/") && className.endsWith("List")) {
        String signature = getSigConstantOperand();
        XField field = getFieldFromStack(stack, signature);
        if (field != null) {
            String fieldName = field.getName();
            FieldInfo fi = fieldsReported.get(fieldName);
            if (fi != null) {
                String methodName = getNameConstantOperand();
                QMethod methodInfo = new QMethod(methodName, signature);
                if (listMethods.contains(methodInfo)) {
                    fieldsReported.remove(fieldName);
                } else if (setMethods.contains(methodInfo)) {
                    fi.addUse(getPC());
                }
            }
        }
    }
}
Also used : QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) XField(edu.umd.cs.findbugs.ba.XField) ToString(com.mebigfatguy.fbcontrib.utils.ToString)

Example 3 with QMethod

use of com.mebigfatguy.fbcontrib.utils.QMethod in project fb-contrib by mebigfatguy.

the class PresizeCollections method sawOpcode.

/**
 * implements the visitor to look for creation of collections that are then populated with a known number of elements usually based on another collection,
 * but the new collection is not presized.
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "CLI_CONSTANT_LIST_INDEX", justification = "Constrained by FindBugs API")
@Override
public void sawOpcode(int seen) {
    PSCUserValue userValue = null;
    boolean sawAlloc = false;
    try {
        stack.precomputation(this);
        switch(seen) {
            case Const.INVOKESPECIAL:
                String clsName = getClassConstantOperand();
                if (PRESIZEABLE_COLLECTIONS.contains(clsName)) {
                    String methodName = getNameConstantOperand();
                    if (Values.CONSTRUCTOR.equals(methodName)) {
                        String signature = getSigConstantOperand();
                        if (SignatureBuilder.SIG_VOID_TO_VOID.equals(signature)) {
                            userValue = new PSCUserValue(Integer.valueOf(nextAllocNumber++));
                            sawAlloc = true;
                        } else if (guavaOnPath && (stack.getStackDepth() > 0)) {
                            FQMethod fqMethod = new FQMethod(clsName, methodName, signature);
                            if (HASHMAP_SIZED_CTOR.equals(fqMethod) || HASHSET_SIZED_CTOR.equals(fqMethod)) {
                                OpcodeStack.Item itm = stack.getStackItem(0);
                                XMethod xm = itm.getReturnValueOf();
                                if ((xm != null) && "size".equals(xm.getMethodDescriptor().getName())) {
                                    bugReporter.reportBug(new BugInstance(this, BugType.PSC_SUBOPTIMAL_COLLECTION_SIZING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                }
                            }
                        }
                    }
                }
                break;
            case Const.INVOKEINTERFACE:
                String methodName = getNameConstantOperand();
                if (ITERATOR_METHOD.equals(new QMethod(methodName, getSigConstantOperand()))) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        userValue = isSizedSource(itm);
                    }
                } else if (ITERATOR_HASNEXT.equals(new FQMethod(getClassConstantOperand(), methodName, getSigConstantOperand()))) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        userValue = (PSCUserValue) itm.getUserValue();
                    }
                } else if ("add".equals(methodName) || "addAll".equals(methodName)) {
                    String signature = getSigConstantOperand();
                    int numArguments = SignatureUtils.getNumParameters(signature);
                    if ((numArguments == 1) && (stack.getStackDepth() > 1)) {
                        OpcodeStack.Item item = stack.getStackItem(1);
                        PSCUserValue uv = (PSCUserValue) item.getUserValue();
                        if (uv != null) {
                            Integer allocNum = uv.getAllocationNumber();
                            if (allocNum != null) {
                                if ("addAll".equals(methodName)) {
                                    allocToAddPCs.remove(allocNum);
                                } else {
                                    List<Integer> lines = allocToAddPCs.get(allocNum);
                                    if (lines == null) {
                                        lines = new ArrayList<>();
                                        allocToAddPCs.put(allocNum, lines);
                                    }
                                    lines.add(Integer.valueOf(getPC()));
                                }
                            }
                        }
                    }
                } else if ("put".equals(methodName) || "putAll".equals(methodName)) {
                    String signature = getSigConstantOperand();
                    int numArguments = SignatureUtils.getNumParameters(signature);
                    if ((numArguments == 2) && (stack.getStackDepth() > 2)) {
                        OpcodeStack.Item item = stack.getStackItem(2);
                        PSCUserValue uv = (PSCUserValue) item.getUserValue();
                        if (uv != null) {
                            Integer allocNum = uv.getAllocationNumber();
                            if (allocNum != null) {
                                if ("putAll".equals(methodName)) {
                                    allocToAddPCs.remove(allocNum);
                                } else {
                                    List<Integer> lines = allocToAddPCs.get(allocNum);
                                    if (lines == null) {
                                        lines = new ArrayList<>();
                                        allocToAddPCs.put(allocNum, lines);
                                    }
                                    lines.add(Integer.valueOf(getPC()));
                                }
                            }
                        }
                    }
                }
                break;
            case Const.INVOKESTATIC:
                FQMethod fqm = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
                if (STATIC_COLLECTION_FACTORIES.contains(fqm)) {
                    userValue = new PSCUserValue(Integer.valueOf(nextAllocNumber++));
                    sawAlloc = true;
                }
                break;
            case Const.LOOKUPSWITCH:
            case Const.TABLESWITCH:
                int[] offsets = getSwitchOffsets();
                if (offsets.length >= 2) {
                    int pc = getPC();
                    int thisOffset = pc + offsets[0];
                    for (int o = 0; o < (offsets.length - 1); o++) {
                        int nextOffset = offsets[o + 1] + pc;
                        CodeRange db = new CodeRange(thisOffset, nextOffset, false);
                        optionalRanges.add(db);
                        thisOffset = nextOffset;
                    }
                }
                break;
            case Const.IFEQ:
            case Const.IFNE:
            case Const.IFLT:
            case Const.IFLE:
            case Const.IF_ICMPEQ:
            case Const.IF_ICMPNE:
            case Const.IF_ICMPLT:
            case Const.IF_ICMPGE:
            case Const.IF_ICMPGT:
            case Const.IF_ICMPLE:
            case Const.IF_ACMPEQ:
            case Const.IF_ACMPNE:
            case Const.GOTO:
            case Const.GOTO_W:
                if (getBranchOffset() < 0) {
                    if (branchBasedOnUnsizedObject(seen)) {
                        break;
                    }
                    int target = getBranchTarget();
                    Iterator<Map.Entry<Integer, List<Integer>>> it = allocToAddPCs.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<Integer, List<Integer>> entry = it.next();
                        Integer allocLoc = allocLocation.get(entry.getKey());
                        if ((allocLoc != null) && (allocLoc.intValue() < target)) {
                            List<Integer> pcs = entry.getValue();
                            for (int pc : pcs) {
                                if (pc > target) {
                                    if (hasSinglePossiblySizedBranch(allocLoc.intValue(), pc)) {
                                        bugReporter.reportBug(new BugInstance(this, BugType.PSC_PRESIZE_COLLECTIONS.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this, pc));
                                        it.remove();
                                    }
                                    break;
                                }
                            }
                        }
                    }
                } else {
                    CodeRange db = new CodeRange(getPC(), getBranchTarget(), !branchBasedOnUnsizedObject(seen));
                    optionalRanges.add(db);
                }
                break;
            case Const.IFNULL:
            case Const.IFNONNULL:
            case Const.IFGE:
            case Const.IFGT:
                // null check and >, >= branches are hard to presize
                if (getBranchOffset() > 0) {
                    CodeRange db = new CodeRange(getPC(), getBranchTarget(), false);
                    optionalRanges.add(db);
                }
                break;
            case Const.ASTORE:
            case Const.ASTORE_0:
            case Const.ASTORE_1:
            case Const.ASTORE_2:
            case Const.ASTORE_3:
                {
                    if (stack.getStackDepth() > 0) {
                        PSCUserValue uv = (PSCUserValue) stack.getStackItem(0).getUserValue();
                        if (uv != null) {
                            storeToUserValue.put(getRegisterOperand(), uv);
                        }
                    }
                }
                break;
            case Const.ALOAD:
            case Const.ALOAD_0:
            case Const.ALOAD_1:
            case Const.ALOAD_2:
            case Const.ALOAD_3:
                {
                    userValue = storeToUserValue.get(getRegisterOperand());
                }
                break;
            case Const.PUTFIELD:
                {
                    if (stack.getStackDepth() > 0) {
                        PSCUserValue uv = (PSCUserValue) stack.getStackItem(0).getUserValue();
                        if (uv != null) {
                            storeToUserValue.put(getNameConstantOperand(), uv);
                        }
                    }
                }
                break;
            case Const.GETFIELD:
                {
                    userValue = storeToUserValue.get(getNameConstantOperand());
                }
        }
    } finally {
        stack.sawOpcode(this, seen);
        if ((userValue != null) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(userValue);
            if (sawAlloc) {
                allocLocation.put(userValue.getAllocationNumber(), Integer.valueOf(getPC()));
            }
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) ArrayList(java.util.ArrayList) BugInstance(edu.umd.cs.findbugs.BugInstance) ToString(com.mebigfatguy.fbcontrib.utils.ToString) QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with QMethod

use of com.mebigfatguy.fbcontrib.utils.QMethod in project fb-contrib by mebigfatguy.

the class SpoiledChildInterfaceImplementor method filterSuperInterfaceMethods.

/**
 * removes methods found in an interface when a super interface having the same methods is implemented in a parent. While this is somewhat hinky, we'll
 * allow it.
 *
 * @param inf
 *            the interface to look for super interfaces for
 * @param infMethods
 *            the remaining methods that are needed to be found
 * @param cls
 *            the super class to look for these methods in
 */
private void filterSuperInterfaceMethods(JavaClass inf, Set<QMethod> infMethods, JavaClass cls) {
    try {
        if (infMethods.isEmpty()) {
            return;
        }
        JavaClass[] superInfs = inf.getInterfaces();
        for (JavaClass superInf : superInfs) {
            if (cls.implementationOf(superInf)) {
                Set<QMethod> superInfMethods = buildMethodSet(superInf);
                infMethods.removeAll(superInfMethods);
                if (infMethods.isEmpty()) {
                    return;
                }
            }
            filterSuperInterfaceMethods(superInf, infMethods, cls);
        }
    } catch (ClassNotFoundException cnfe) {
        bugReporter.reportMissingClass(cnfe);
        infMethods.clear();
    }
}
Also used : QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) JavaClass(org.apache.bcel.classfile.JavaClass)

Example 5 with QMethod

use of com.mebigfatguy.fbcontrib.utils.QMethod in project fb-contrib by mebigfatguy.

the class SpoiledChildInterfaceImplementor method visitClassContext.

/**
 * looks for classes that implement interfaces but don't provide those methods
 *
 * @param classContext
 *            the context object of the currently parsed class
 */
@Override
public void visitClassContext(ClassContext classContext) {
    try {
        JavaClass cls = classContext.getJavaClass();
        if (cls.isAbstract() || cls.isInterface()) {
            return;
        }
        if (Values.DOTTED_JAVA_LANG_OBJECT.equals(cls.getSuperclassName())) {
            return;
        }
        JavaClass[] infs = cls.getInterfaces();
        if (infs.length > 0) {
            Set<QMethod> clsMethods = buildMethodSet(cls);
            for (JavaClass inf : infs) {
                Set<QMethod> infMethods = buildMethodSet(inf);
                if (!infMethods.isEmpty()) {
                    infMethods.removeAll(clsMethods);
                    if (!infMethods.isEmpty()) {
                        JavaClass superCls = cls.getSuperClass();
                        filterSuperInterfaceMethods(inf, infMethods, superCls);
                        if (!infMethods.isEmpty() && !superCls.implementationOf(inf)) {
                            int priority = AnalysisContext.currentAnalysisContext().isApplicationClass(superCls) ? NORMAL_PRIORITY : LOW_PRIORITY;
                            BugInstance bi = new BugInstance(this, BugType.SCII_SPOILED_CHILD_INTERFACE_IMPLEMENTOR.name(), priority).addClass(cls).addString("Implementing interface: " + inf.getClassName()).addString("Methods:");
                            for (QMethod methodInfo : infMethods) {
                                bi.addString('\t' + methodInfo.toString());
                            }
                            bugReporter.reportBug(bi);
                            return;
                        }
                    }
                }
            }
        }
    } catch (ClassNotFoundException cnfe) {
        bugReporter.reportMissingClass(cnfe);
    }
}
Also used : QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) JavaClass(org.apache.bcel.classfile.JavaClass) BugInstance(edu.umd.cs.findbugs.BugInstance)

Aggregations

QMethod (com.mebigfatguy.fbcontrib.utils.QMethod)14 BugInstance (edu.umd.cs.findbugs.BugInstance)7 OpcodeStack (edu.umd.cs.findbugs.OpcodeStack)6 ToString (com.mebigfatguy.fbcontrib.utils.ToString)5 HashMap (java.util.HashMap)5 Map (java.util.Map)4 JavaClass (org.apache.bcel.classfile.JavaClass)4 FQMethod (com.mebigfatguy.fbcontrib.utils.FQMethod)2 FieldAnnotation (edu.umd.cs.findbugs.FieldAnnotation)2 SourceLineAnnotation (edu.umd.cs.findbugs.SourceLineAnnotation)2 XMethod (edu.umd.cs.findbugs.ba.XMethod)2 AbstractMap (java.util.AbstractMap)2 HashSet (java.util.HashSet)2 Method (org.apache.bcel.classfile.Method)2 ImmutabilityType (com.mebigfatguy.fbcontrib.collect.ImmutabilityType)1 MethodInfo (com.mebigfatguy.fbcontrib.collect.MethodInfo)1 StopOpcodeParsingException (com.mebigfatguy.fbcontrib.utils.StopOpcodeParsingException)1 UnmodifiableSet (com.mebigfatguy.fbcontrib.utils.UnmodifiableSet)1 XField (edu.umd.cs.findbugs.ba.XField)1 FieldDescriptor (edu.umd.cs.findbugs.classfile.FieldDescriptor)1