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);
}
}
}
}
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);
}
}
}
}
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);
}
}
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;
}
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);
}
}
Aggregations