Chris Grindstaff 写了一篇文章FindBugs,第 2 部分:编写自定义检测器,他在其中描述了如何使用BCEL添加您自己的规则。(BCEL 不是唯一的字节码库——但它是 FindBugs 使用的。)
下面的代码发出方法访问静态方法或字段的任何情况。您可以在任何实现Runnable的类型上运行它。
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();
}
}
此代码发出以下内容:
==========================
method:<init>
==========================
method:run
static access:access$0
on type:StopThread
然后可以扫描StopThread类型,找到该字段并检查它是否是volatile。
检查同步是可能的,但由于多个 MONITOREXIT 条件可能会变得棘手。向上调用堆栈也可能很困难,但这不是一个微不足道的问题。但是,我认为如果始终如一地实施,检查错误模式会相对容易。
在您找到BCELifier类之前,BCEL 看起来很少有文档记录并且非常麻烦。如果你在一个类上运行它,它会吐出你将如何在 BCEL 中构建类的 Java 源代码。在StopThread上运行它可以生成access$0合成访问器:
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();
}