编写检测器以搜索“ System.out.println”的使用。使用Findbugs [英] Writing a detector to search for uses of "System.out.println" using Findbugs

查看:120
本文介绍了编写检测器以搜索“ System.out.println”的使用。使用Findbugs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个错误检测器,以使用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的调用,将 System.out压入堆栈。调用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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆