ET1*_*T13 5 java bytecode findbugs
我正在尝试使用Findbugs编写一个错误检测器来查找方法调用"System.out.println"的实例.
据我所知,字节码中的"System.out.println"被编译为对GETSTATIC的调用,后者将"System.out"推送到堆栈上.对INVOKEVIRTUAL的调用会从堆栈中弹出"System.out"并调用该方法.
我准备了一些代码(如下所示),它找到了正确的GETSTATIC和INVOKEVIRTUAL调用,但是无法将两者连接在一起.我怀疑我可能需要以某种方式使用OpcodeStack,但我很难理解如何使用它.任何帮助,将不胜感激.
@Override
public void sawOpcode(int seen) {
// if opcode is getstatic
if (seen == GETSTATIC) {
String clsName = getClassConstantOperand();
if ("java/lang/System".equals(clsName)) {
String fldName = getNameConstantOperand();
if ("out".equals(fldName)) {
System.out.println("SYSTEM.OUT here");
}
}
}
// if opcode is invokevirtual
if (seen == INVOKEVIRTUAL) {
String cls = getDottedClassConstantOperand();
if ("java.io.PrintStream".equals(cls)) {
String methodName = getNameConstantOperand();
if ("println".equals(methodName)) {
bugReporter.reportBug(new BugInstance("SYSTEM_OUT_PRINTLN",
NORMAL_PRIORITY).addClassAndMethod(this)
.addSourceLine(this));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我发现,对于我的用例,足以确定是否使用了 System.out 或 System.err - 在 99% 的情况下,这些将用于稍后在块中调用 .print 或 .println。我的检测器检测到加载 System.err 或 System.out 的 GET_STATIC 操作码。下面的代码显示了确定这种情况发生的 3 种替代方法。
package my.findbugs.detectors.forbiddencalls;
import org.apache.log4j.Logger; // it is not trivial to use a logger with FindBugs in Eclipse, leave it out if there are problems
import my.findbugs.detectors.util.DetectorUtil;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.FieldDescriptor;
public class CallToSystemOutPrintlnDetector2 extends OpcodeStackDetector {
private static final Logger LOGGER = Logger.getLogger(CallToSystemOutPrintlnDetector2.class);
private BugReporter bugReporter;
public CallToSystemOutPrintlnDetector2(BugReporter bugReporter) {
super();
this.bugReporter = bugReporter;
LOGGER.debug("Instantiated.");
}
public void sawOpcode(int seen) {
// find occurrences of:
//2: getstatic #54; //Field java/lang/System.out:Ljava/io/PrintStream;
//2: getstatic #54; //Field java/lang/System.out:Ljava/io/PrintStream;
if (seen == GETSTATIC){
try {
// LOGGER.debug(operand); // static java.lang.System.out Ljava/io/PrintStream;
// LOGGER.debug(operand.getClass()); // class edu.umd.cs.findbugs.classfile.analysis.FieldInfo
// LOGGER.debug(operand.getName()); // err
// LOGGER.debug(operand.getClassDescriptor()); // java/lang/System
// LOGGER.debug(operand.getSignature()); // Ljava/io/PrintStream;
FieldDescriptor operand = getFieldDescriptorOperand();
ClassDescriptor classDescriptor = operand.getClassDescriptor();
if ("java/lang/System".equals(classDescriptor.getClassName()) &&
("err".equals(operand.getName())||"out".equals(operand.getName()))) {
reportBug();
}
} catch (Exception e) {
//ignore
}
// could be used
// try {
// MethodDescriptor operand = getMethodDescriptorOperand();
// LOGGER.debug(operand); // java.lang.System.outLjava/io/PrintStream;
// LOGGER.debug(operand.getClass()); // class edu.umd.cs.findbugs.classfile.MethodDescriptor
// LOGGER.debug(operand.getName()); // err
// LOGGER.debug(operand.getClassDescriptor()); // java/lang/System
// LOGGER.debug(operand.getSignature()); // Ljava/io/PrintStream;
// } catch (Exception e) {
// //ignore
// }
// could be used
// try {
// String operand = getRefConstantOperand();
// LOGGER.debug(operand); // java.lang.System.out : Ljava.io.PrintStream;
// if (operand != null && (
// operand.startsWith("java.lang.System.out :") || operand.startsWith("java.lang.System.err :"))) {
// reportBug();
// }
// } catch (Exception e) {
// //ignore
// }
}
}
private void reportBug(){
this.bugReporter.reportBug(getBugInstance());
}
private BugInstance getBugInstance() {
return new BugInstance(this, "MY_CALL_TO_SYSTEM_OUT_BUG", DetectorUtil.MY_PRIORITY)
.addClassAndMethod(this)
.addSourceLine(this);
}
}
Run Code Online (Sandbox Code Playgroud)