问题描述
我正在尝试编写一个错误检测器,以使用Findbugs查找方法调用 System.out.println的实例。
I am trying to write a bug detector to find instances of the method call "System.out.println" using Findbugs.
我知道字节码中的 System.out.println被编译为对GETSTATIC的调用,。调用INVOKEVIRTUAL会将 System.out弹出堆栈并调用该方法。
I understand that "System.out.println" in bytecode is compiled to a call to GETSTATIC, which pushes "System.out" onto the stack. A call to INVOKEVIRTUAL pops "System.out" off the stack and calls the method.
我准备了一些代码(如下所示),可以找到正确的GETSTATIC和INVOKEVIRTUAL调用,但是无法将两者链接在一起。我怀疑我可能需要以某种方式使用OpcodeStack,但是在理解如何使用它方面遇到了麻烦。任何帮助,将不胜感激。
I have prepared some code (found below) which finds the correct GETSTATIC and INVOKEVIRTUAL calls, but have been unable to link the two together. I suspect I may need to use OpcodeStack in some way, but am having trouble in understanding how I can use it. Any help would be appreciated.
@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));
}
}
}
}
推荐答案
我发现,对于我的用例来说,足以确定完全使用了System.out或System.err -在99%在某些情况下,这些将用于稍后在代码块中调用.print或.println。我的检测器检测到加载System.err或System.out的GET_STATIC操作码。下面的代码显示了确定发生这种情况的3种选择。
I found that, for my use case, it is enough to determine that System.out or System.err are used at all - in 99% of cases, these will be used for calling .print or .println later in the block. My detector detects GET_STATIC opcodes that load System.err or System.out. The code is below, showing 3 alternatives of determining that this occurs.
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);
}
}
这篇关于编写检测器以搜索“ System.out.println”的使用。使用Findbugs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!