当前位置: 首页 > 面试题库 >

编写检测器以使用Findbugs搜索“ System.out.println”的用途

阚元白
2023-03-14
问题内容

我正在尝试编写一个错误检测器,以使用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)); 
                            } 
                    } 
            }

    }

问题答案:

我发现,对于我的用例而言, 足以确定完全使用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);
    }

}


 类似资料:
  • 问题内容: 如何使用php检测搜索引擎机器人? 问题答案: 这是Search Engine Directory of Spider names 然后使用来检查代理是否被称为蜘蛛。

  • 我正在为一个解释器编写测试,该解释器需要大量语法上有效的输入。这是我如何做的一个最小的例子: 处理panic的想法来自https://golang.org/doc/entiful_go#recover,但是我不知道在测试中使用它是否像上面的示例中那样是一种好的做法,或者有某种原因,为什么在修复运行时错误之前,最好让测试失败。 这种设置的好处是,我可以看到所有TestCase会发生什么,即使其中一个

  • 我有很多使用Lombok生成器的字段的类。 但是,这为调用方提供了在不设置的情况下创建对象的选项,如果使用该选项,将导致运行时失败。 我正在寻找在构建时捕捉这些错误的方法。 有一些非Lombok的方法,比如StepBuilder,甚至是构造函数来确保总是设置强制字段,但我对使用Lombok Builder实现这一点的方法感兴趣。 此外,我理解为了进行编译时检查而设计类(如step-builder或

  • 本文向大家介绍编写Golang程序以搜索数组中的元素,包括了编写Golang程序以搜索数组中的元素的使用技巧和注意事项,需要的朋友参考一下 定义: 一个数字是大于2且只能被其自身和1整除。 示例:素 数是2、3、5、7、11、13、113、119等。 解决这个问题的方法 步骤1:找到给定数字的平方根sq_root =√num 步骤2:如果给定数字可被[2,sq_root]所属的数字整除,则打印“非

  • 问题内容: 当前试图用a编写select语句,并且搜索条件使我有些悲痛。 目的是搜索具有3种不同参数类型的表,并相应地对输出进行排名。(下面是我的代码示例) 关键搜索条件(必须且加权为1) 其他必备(加权.8) 很高兴(加权.5) SQL: 上面的语句不返回任何内容,我怀疑它是否有可能以上述方式堆叠术语。 返回的结果必须同时拥有会计和经理,并且很高兴拥有Excel 有什么建议可以实现这一目标吗?

  • 问题内容: 我正在将Java应用程序的ORM的Hibernate用于Oracle数据库(并不是数据库供应商很重要,有一天我们可能会切换到另一个数据库),我想根据用户提供的字符串从数据库中检索对象。例如,在搜索人员时,如果用户正在寻找居住在“ fran”中的人员,我希望能够将其人员提供给旧金山。 SQL不是我的强项,我更喜欢Hibernate的构建代码,而不是硬编码的字符串。谁能指出正确的方向,说明