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