Search in sources :

Example 6 with FQMethod

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

the class OptionalIssues method sawOpcode.

/**
 * implements the visitor to look for reference compares of Optional, Optional use when more specific Optionals should be used, and use of orElse when
 * orElseGet would be more appropriate
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@Override
public void sawOpcode(int seen) {
    FQMethod curCalledMethod = null;
    Boolean sawPlainOptional = null;
    try {
        switch(seen) {
            case Const.IFNULL:
            case Const.IFNONNULL:
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    if ("Ljava/util/Optional;".equals(itm.getSignature())) {
                        bugReporter.reportBug(new BugInstance(this, BugType.OI_OPTIONAL_ISSUES_CHECKING_REFERENCE.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                    }
                }
                break;
            case Const.INVOKEDYNAMIC:
                // smells like a hack. Not sure how to do this better
                ConstantInvokeDynamic id = (ConstantInvokeDynamic) getConstantRefOperand();
                ConstantPool cp = getConstantPool();
                ConstantNameAndType nameAndType = (ConstantNameAndType) cp.getConstant(id.getNameAndTypeIndex());
                ConstantUtf8 typeConstant = (ConstantUtf8) cp.getConstant(nameAndType.getSignatureIndex());
                curCalledMethod = new FQMethod(getClassName(), "lambda$" + id.getBootstrapMethodAttrIndex(), typeConstant.getBytes());
                break;
            case Const.INVOKESTATIC:
            case Const.INVOKEINTERFACE:
            case Const.INVOKESPECIAL:
                String clsName = getClassConstantOperand();
                String methodName = getNameConstantOperand();
                curCalledMethod = new FQMethod(clsName, methodName, getSigConstantOperand());
                if ("java/util/Optional".equals(clsName) && "of".equals(methodName)) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        String itmSig = itm.getSignature();
                        if (BOXED_OPTIONAL_TYPES.contains(itmSig)) {
                            bugReporter.reportBug(new BugInstance(this, BugType.OI_OPTIONAL_ISSUES_PRIMITIVE_VARIANT_PREFERRED.name(), LOW_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        }
                    }
                }
                break;
            case Const.INVOKEVIRTUAL:
                curCalledMethod = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
                if (OR_ELSE_METHODS.contains(curCalledMethod)) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        if ((itm.getRegisterNumber() < 0) && (itm.getReturnValueOf() != null) && !isTrivialStackOps()) {
                            bugReporter.reportBug(new BugInstance(this, BugType.OI_OPTIONAL_ISSUES_USES_IMMEDIATE_EXECUTION.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        }
                    }
                    if (OPTIONAL_OR_ELSE_METHOD.equals(curCalledMethod)) {
                        sawPlainOptional = Boolean.TRUE;
                    }
                } else if (OR_ELSE_GET_METHODS.contains(curCalledMethod)) {
                    if (!activeStackOps.isEmpty()) {
                        ActiveStackOp op = activeStackOps.getLast();
                        FQMethod method = op.getMethod();
                        if (method == null) {
                            bugReporter.reportBug(new BugInstance(this, BugType.OI_OPTIONAL_ISSUES_USES_ORELSEGET_WITH_NULL.name(), LOW_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        } else {
                            Method getMethod = getLambdaMethod(method.getMethodName());
                            if (getMethod != null) {
                                byte[] byteCode = getMethod.getCode().getCode();
                                if (byteCode.length <= 4) {
                                    // we are looking for ALOAD, GETFIELD, or LDC followed by ARETURN, that should fit in 4 bytes
                                    if (!hasInvoke(byteCode)) {
                                        bugReporter.reportBug(new BugInstance(this, BugType.OI_OPTIONAL_ISSUES_USES_DELAYED_EXECUTION.name(), LOW_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                    }
                                }
                            }
                        }
                    }
                    if (OPTIONAL_OR_ELSE_GET_METHOD.equals(curCalledMethod)) {
                        sawPlainOptional = Boolean.TRUE;
                    }
                } else if (OPTIONAL_GET_METHOD.equals(curCalledMethod)) {
                    sawPlainOptional = Boolean.TRUE;
                }
                break;
        }
    } finally {
        stack.sawOpcode(this, seen);
        int stackDepth = stack.getStackDepth();
        if (stackDepth == 0) {
            activeStackOps.clear();
        } else {
            activeStackOps.addLast(new ActiveStackOp(seen, curCalledMethod));
            while (activeStackOps.size() > stackDepth) {
                activeStackOps.removeFirst();
            }
            if (sawPlainOptional != null) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                itm.setUserValue(sawPlainOptional);
            }
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) BugInstance(edu.umd.cs.findbugs.BugInstance) ToString(com.mebigfatguy.fbcontrib.utils.ToString) Method(org.apache.bcel.classfile.Method) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ConstantUtf8(org.apache.bcel.classfile.ConstantUtf8) ConstantNameAndType(org.apache.bcel.classfile.ConstantNameAndType) ConstantPool(org.apache.bcel.classfile.ConstantPool) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ConstantInvokeDynamic(org.apache.bcel.classfile.ConstantInvokeDynamic)

Example 7 with FQMethod

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

the class OverlyPermissiveMethod method report.

/**
 * after collecting all method calls, build a report of all methods that have been called, but in a way that is less permissive then is defined.
 */
@Override
public void report() {
    for (Map.Entry<FQMethod, MethodInfo> entry : Statistics.getStatistics()) {
        MethodInfo mi = entry.getValue();
        int declaredAccess = mi.getDeclaredAccess();
        if ((declaredAccess & Const.ACC_PRIVATE) != 0) {
            continue;
        }
        if (mi.wasCalledPublicly() || !mi.wasCalled()) {
            continue;
        }
        FQMethod key = entry.getKey();
        String methodName = key.getMethodName();
        if (isGetterSetter(methodName, key.getSignature())) {
            continue;
        }
        if (isOverlyPermissive(declaredAccess) && !isConstrainedByInterface(key)) {
            try {
                String clsName = key.getClassName();
                if (!isDerived(Repository.lookupClass(clsName), key)) {
                    BugInstance bi = new BugInstance(this, BugType.OPM_OVERLY_PERMISSIVE_METHOD.name(), LOW_PRIORITY).addClass(clsName).addMethod(clsName, key.getMethodName(), key.getSignature(), (declaredAccess & Const.ACC_STATIC) != 0);
                    String descr = String.format("- Method declared %s but could be declared %s", getDeclaredAccessValue(declaredAccess), getRequiredAccessValue(mi));
                    bi.addString(descr);
                    bugReporter.reportBug(bi);
                }
            } catch (ClassNotFoundException cnfe) {
                bugReporter.reportMissingClass(cnfe);
            }
        }
    }
}
Also used : FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) BugInstance(edu.umd.cs.findbugs.BugInstance) MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo) HashMap(java.util.HashMap) Map(java.util.Map)

Example 8 with FQMethod

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

the class MapUsageIssues method sawOpcode.

@Override
public void sawOpcode(int seen) {
    try {
        if (!mapContainsKeyUsed.isEmpty()) {
            Iterator<Map.Entry<MapRef, ContainsKey>> it = mapContainsKeyUsed.entrySet().iterator();
            int pc = getPC();
            while (it.hasNext()) {
                Map.Entry<MapRef, ContainsKey> entry = it.next();
                if (!entry.getKey().isValid() || entry.getValue().outOfScope(pc)) {
                    it.remove();
                }
            }
        }
        // checking for a branch might be overkill, but for now lets go with it
        if (!mapGetUsed.isEmpty() && OpcodeUtils.isBranch(seen)) {
            Iterator<Map.Entry<MapRef, Get>> it = mapGetUsed.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<MapRef, Get> entry = it.next();
                it.remove();
            }
        }
        if ((seen == Const.IFNULL) || (seen == Const.IFNONNULL)) {
            if (stack.getStackDepth() > 0) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                XMethod method = itm.getReturnValueOf();
                if ((method != null) && (mapClass != null)) {
                    if (COLLECTION_ACCESSORS.contains(method.getName())) {
                        JavaClass cls = Repository.lookupClass(method.getClassName());
                        if (cls.implementationOf(mapClass)) {
                            bugReporter.reportBug(new BugInstance(this, BugType.MUI_NULL_CHECK_ON_MAP_SUBSET_ACCESSOR.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        }
                    }
                }
            }
        } else if (seen == Const.INVOKEINTERFACE) {
            FQMethod fqm = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
            if (CONTAINS_METHOD.equals(fqm)) {
                if (stack.getStackDepth() >= 2) {
                    OpcodeStack.Item item = stack.getStackItem(1);
                    if ((item.getRegisterNumber() < 0) && (item.getXField() == null)) {
                        XMethod xm = item.getReturnValueOf();
                        if ((xm != null) && COLLECTION_ACCESSORS.contains(xm.getName()) && Values.DOTTED_JAVA_UTIL_MAP.equals(xm.getClassName())) {
                            bugReporter.reportBug(new BugInstance(this, BugType.MUI_USE_CONTAINSKEY.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        }
                    }
                }
            } else if (CONTAINSKEY_METHOD.equals(fqm)) {
                if (getNextOpcode() == Const.IFEQ) {
                    int ifEnd = getNextPC() + CodeByteUtils.getshort(getCode().getCode(), getNextPC() + 1);
                    if (stack.getStackDepth() >= 2) {
                        OpcodeStack.Item itm = stack.getStackItem(1);
                        mapContainsKeyUsed.put(new MapRef(itm), new ContainsKey(stack.getStackItem(0), ifEnd));
                    }
                }
            } else if (GET_METHOD.equals(fqm)) {
                if (stack.getStackDepth() >= 2) {
                    OpcodeStack.Item itm = stack.getStackItem(1);
                    ContainsKey ck = mapContainsKeyUsed.remove(new MapRef(itm));
                    if ((ck != null) && new ContainsKey(stack.getStackItem(0), 0).equals(ck)) {
                        bugReporter.reportBug(new BugInstance(this, BugType.MUI_CONTAINSKEY_BEFORE_GET.name(), ck.getReportLevel()).addClass(this).addMethod(this).addSourceLine(this));
                    }
                    mapGetUsed.put(new MapRef(itm), new Get(stack.getStackItem(0)));
                }
            } else if (REMOVE_METHOD.equals(fqm)) {
                if (stack.getStackDepth() >= 2) {
                    OpcodeStack.Item itm = stack.getStackItem(1);
                    Get get = mapGetUsed.remove(new MapRef(itm));
                    if ((get != null) && new Get(stack.getStackItem(0)).equals(get)) {
                        bugReporter.reportBug(new BugInstance(this, BugType.MUI_GET_BEFORE_REMOVE.name(), get.getReportLevel()).addClass(this).addMethod(this).addSourceLine(this));
                    }
                }
            }
            QMethod qm = new QMethod(getNameConstantOperand(), getSigConstantOperand());
            if (SIZE_METHOD.equals(qm)) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    if ((itm.getRegisterNumber() < 0) && (itm.getXField() == null)) {
                        XMethod xm = itm.getReturnValueOf();
                        if ((xm != null) && Values.DOTTED_JAVA_UTIL_MAP.equals(xm.getClassName()) && COLLECTION_ACCESSORS.contains(xm.getName())) {
                            bugReporter.reportBug(new BugInstance(this, BugType.MUI_CALLING_SIZE_ON_SUBCONTAINER.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                        }
                    }
                }
            }
        }
    } catch (ClassNotFoundException e) {
        bugReporter.reportMissingClass(e);
    } finally {
        stack.sawOpcode(this, seen);
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) BugInstance(edu.umd.cs.findbugs.BugInstance) QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) JavaClass(org.apache.bcel.classfile.JavaClass) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) HashMap(java.util.HashMap) Map(java.util.Map)

Example 9 with FQMethod

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

the class BloatedAssignmentScope method isRiskyMethodCall.

public boolean isRiskyMethodCall() {
    String clsName = getClassConstantOperand();
    if (dangerousAssignmentClassSources.contains(clsName)) {
        return true;
    }
    FQMethod key = new FQMethod(clsName, getNameConstantOperand(), getSigConstantOperand());
    if (dangerousAssignmentMethodSources.contains(key)) {
        return true;
    }
    String sig = key.toFQMethodSignature();
    for (Pattern p : dangerousAssignmentMethodPatterns) {
        Matcher m = p.matcher(sig);
        if (m.matches()) {
            return true;
        }
    }
    return false;
}
Also used : Pattern(java.util.regex.Pattern) Matcher(java.util.regex.Matcher) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ToString(com.mebigfatguy.fbcontrib.utils.ToString)

Example 10 with FQMethod

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

the class CharsetIssues method sawOpcode.

/**
 * implements the visitor to look for method calls that take a parameter that either represents a encoding via a string, or takes a Charset. If the method
 * can take both, and a string is presented for a standard charset available in jdk 7, and the code is compiled against 7, then report. It also looks for
 * mistakes, encodings that aren't recognized in the current jvm.
 *
 * @param seen
 *            the currently parsed opcode
 */
@Override
public void sawOpcode(int seen) {
    try {
        stack.precomputation(this);
        switch(seen) {
            case Const.INVOKESPECIAL:
            case Const.INVOKESTATIC:
            case Const.INVOKEINTERFACE:
            case Const.INVOKEVIRTUAL:
                String encoding = null;
                String className = getClassConstantOperand();
                String methodName = getNameConstantOperand();
                String methodSig = getSigConstantOperand();
                FQMethod methodInfo = new FQMethod(className, methodName, methodSig);
                Integer stackOffset = REPLACEABLE_ENCODING_METHODS.get(methodInfo);
                if (stackOffset != null) {
                    int offset = stackOffset.intValue();
                    if (stack.getStackDepth() > offset) {
                        OpcodeStack.Item item = stack.getStackItem(offset);
                        encoding = (String) item.getConstant();
                        if (encoding != null) {
                            encoding = encoding.toUpperCase(Locale.ENGLISH);
                            if ((classVersion >= Const.MAJOR_1_7) && STANDARD_JDK7_ENCODINGS.contains(encoding)) {
                                // the counts put in the Pair are indexed from
                                // the beginning of
                                String changedMethodSig = replaceNthArgWithCharsetString(methodSig, offset);
                                bugReporter.reportBug(new BugInstance(this, BugType.CSI_CHAR_SET_ISSUES_USE_STANDARD_CHARSET.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this).addCalledMethod(this).addCalledMethod(className, methodName, changedMethodSig, seen == Const.INVOKESTATIC));
                            }
                        }
                    }
                } else {
                    Integer offsetValue = UNREPLACEABLE_ENCODING_METHODS.get(methodInfo);
                    if (offsetValue != null) {
                        int offset = offsetValue.intValue();
                        if (stack.getStackDepth() > offset) {
                            OpcodeStack.Item item = stack.getStackItem(offset);
                            encoding = (String) item.getConstant();
                            if (encoding != null) {
                                encoding = encoding.toUpperCase(Locale.ENGLISH);
                                if ((classVersion >= Const.MAJOR_1_7) && STANDARD_JDK7_ENCODINGS.contains(encoding)) {
                                    bugReporter.reportBug(new BugInstance(this, BugType.CSI_CHAR_SET_ISSUES_USE_STANDARD_CHARSET_NAME.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this).addCalledMethod(this));
                                }
                            }
                        }
                    }
                }
                if (encoding != null) {
                    try {
                        Charset.forName(encoding);
                    } catch (IllegalArgumentException e) {
                        // encompasses both
                        // IllegalCharsetNameException
                        // and
                        // UnsupportedCharsetException
                        bugReporter.reportBug(new BugInstance(this, BugType.CSI_CHAR_SET_ISSUES_UNKNOWN_ENCODING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this).addCalledMethod(this).addString(encoding));
                    }
                }
                break;
            default:
                break;
        }
    } finally {
        stack.sawOpcode(this, seen);
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) BugInstance(edu.umd.cs.findbugs.BugInstance)

Aggregations

FQMethod (com.mebigfatguy.fbcontrib.utils.FQMethod)25 OpcodeStack (edu.umd.cs.findbugs.OpcodeStack)15 BugInstance (edu.umd.cs.findbugs.BugInstance)13 XMethod (edu.umd.cs.findbugs.ba.XMethod)7 ToString (com.mebigfatguy.fbcontrib.utils.ToString)6 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Method (org.apache.bcel.classfile.Method)3 MethodInfo (com.mebigfatguy.fbcontrib.collect.MethodInfo)2 QMethod (com.mebigfatguy.fbcontrib.utils.QMethod)2 JavaClass (org.apache.bcel.classfile.JavaClass)2 Statistics (com.mebigfatguy.fbcontrib.collect.Statistics)1 XField (edu.umd.cs.findbugs.ba.XField)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Matcher (java.util.regex.Matcher)1 Pattern (java.util.regex.Pattern)1 Nullable (javax.annotation.Nullable)1 AnnotationEntry (org.apache.bcel.classfile.AnnotationEntry)1 BootstrapMethod (org.apache.bcel.classfile.BootstrapMethod)1