Chris Grindstaff schrieb einen Artikel FindBugs, Part 2: Writing custom detectors, in dem er beschreibt, wie die BCEL benutzen, um Ihre eigenen Regeln hinzuzufügen. (BCEL ist nicht die einzige Bytecode-Bibliothek - aber es ist die von FindBugs verwendete.)
Der folgende Code gibt Fälle aus, in denen eine Methode auf eine statische Methode oder ein Feld zugreift. Sie können es auf jedem Typ ausführen, der Runnable implementiert.
public class StaticInvocationFinder extends EmptyVisitor {
@Override
public void visitMethod(Method obj) {
System.out.println("==========================");
System.out.println("method:" + obj.getName());
Code code = obj.getCode();
InstructionList instructions = new InstructionList(code.getCode());
for (Instruction instruction : instructions.getInstructions()) {
// static field or method
if (Constants.INVOKESTATIC == instruction.getOpcode()) {
if (instruction instanceof InvokeInstruction) {
InvokeInstruction invokeInstruction = (InvokeInstruction) instruction;
ConstantPoolGen cpg = new ConstantPoolGen(obj
.getConstantPool());
System.out.println("static access:"
+ invokeInstruction.getMethodName(cpg));
System.out.println(" on type:"
+ invokeInstruction.getReferenceType(cpg));
}
}
}
instructions.dispose();
}
public static void main(String[] args) throws Exception {
JavaClass javaClass = Repository.lookupClass("StopThread$1");
StaticInvocationFinder visitor = new StaticInvocationFinder();
DescendingVisitor classWalker = new DescendingVisitor(javaClass,
visitor);
classWalker.visit();
}
}
Dieser Code gibt das folgende:
==========================
method:<init>
==========================
method:run
static access:access$0
on type:StopThread
Es wäre möglich, den Typ StopThread, finden Sie das Feld dann zu scannen und überprüfen, um zu sehen, ob es flüchtigen ist.
Die Überprüfung auf Synchronisierung ist möglich, kann jedoch aufgrund mehrerer MONITOREXIT-Bedingungen schwierig werden. Steigende Call-Stacks könnten auch schwierig sein, aber das ist kein triviales Problem. Ich denke jedoch, dass es relativ einfach wäre, nach einem Fehlermuster zu suchen, wenn es konsistent implementiert wurde.
BCEL sieht spärlich dokumentiert und wirklich haarig, bis Sie die BCELifier Klasse finden. Wenn Sie es für eine Klasse ausführen, spuckt es eine Java-Quelle aus, wie Sie die Klasse in BCEL erstellen würden.Laufen sie auf StopThread ergibt dies für die Erzeugung des Zugang $ 0 synthetischen Accessor:
private void createMethod_2() {
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_STATIC | ACC_SYNTHETIC, Type.BOOLEAN, Type.NO_ARGS, new String[] { }, "access$0", "StopThread", il, _cp);
InstructionHandle ih_0 = il.append(_factory.createFieldAccess("StopThread", "stopRequested", Type.BOOLEAN, Constants.GETSTATIC));
il.append(_factory.createReturn(Type.INT));
method.setMaxStack();
method.setMaxLocals();
_cg.addMethod(method.getMethod());
il.dispose();
}
FindBugs erkennt das obige "StopThread" -Ausgabe nicht. – auramo
@auramo: das könnte stimmen, aber es prüft auf eine Reihe anderer Bedingungen. Und wie gesagt, auf diese Tools kann man sich nicht vollständig verlassen. –