静态代码扫描 (三)——FindBugs 自定义规则入门

这是静态代码扫描系列文章的第三篇,前两篇文章介绍了如何使用PMD自定义规则。

  • 静态代码扫描 (一)——PMD 自定义规则入门
  • 静态代码扫描 (二)——PMD 自定义规则实践

阅读本文前,建议先了解一下FindBugs的介绍和使用方法。

准备工作

由于FindBugs是分析编译后的class文件,也就是字节码文件。我们需要了解FindBugs底层的处理机制。根据FindBugs官网文档描述,FindBugs使用了BCEL来分析Java字节码文件。从1.1版本开始,FindBugs也支持使用ASM字节码框架来编写bug探测器。
我们需要下载FindBugs源码版用来新增自定义探测器:findbugs-3.0.1-source.zip
也需要下载FindBugs标准版:findbugs-3.0.1.zip,将findbugs.jar替换为我们的自定义版本后,运行查看结果。

自定义规则

自定义规则思路:

  1. 明确要定义的规则。
  2. 分析样例代码的字节码内容。
  3. 编写探测器。
  4. 将规则加入规则文件中。

1. 明确要定义的规则

我将以一个非常简单的规则举例:代码中避免使用有类似System.out的输出语句。

package main;

public class TestFindBugs {
    public static void main(String[] args) {
        System.out.println("123"); //bug
        System.err.println("123"); //bug
    }
}

2. 分析样例代码的字节码内容

为了更方便的分析样例代码的字节码内容,这里推荐一个Eclipse上用来查看java文件字节码内容的插件:
Bytecode Outline
官网地址:http://andrei.gmxhome.de/bytecode/index.html
在安装完成后,通过Bytecode工具编译后的字节码文件内容:

// class version 51.0 (51)
// access flags 0x21
public class main/TestFindBugs {

  // compiled from: TestFindBugs.java

  // access flags 0x1
  public ()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object. ()V
    RETURN
   L1
    LOCALVARIABLE this Lmain/TestFindBugs; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 5 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "123"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 6 L1
    GETSTATIC java/lang/System.err : Ljava/io/PrintStream;
    LDC "123"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L2
    LINENUMBER 7 L2
    RETURN
   L3
    LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
    MAXSTACK = 2
    MAXLOCALS = 1
}

通过查看字节码文件分析,我们找到了一些关键语句:
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
GETSTATIC java/lang/System.err : Ljava/io/PrintStream;

3. 编写探测器

我们通过刚才找到的关键语句,结合我们的逻辑,进行探测器编写:

package edu.umd.cs.findbugs.detect;

import org.apache.bcel.classfile.Code;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;

/**
 * @author yuanwei3-iri
 * @category 代码中避免使用有类似System.out的输出语句
 */
public class ForbiddenSystemClass extends OpcodeStackDetector {
    BugReporter bugReporter;

    public ForbiddenSystemClass(BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }

    /**
     * visit方法,在每次进入字节码方法的时候调用 在每次进入新方法的时候清空标志位
     */
    @Override
    public void visit(Code obj) {
        super.visit(obj);
    }

    /**
     * 每扫描一条字节码就会进入sawOpcode方法
     * 
     * @param seen
     *            字节码的枚举值
     */
    @Override
    public void sawOpcode(int seen) {
        if (seen == GETSTATIC) {
            if (getClassConstantOperand().equals("java/lang/System")) {
                if(getNameConstantOperand().equals("out") || getNameConstantOperand()
                        .equals("err")){
                    BugInstance bug = new BugInstance(this, "CJ_SYSTEMCLASS",
                            NORMAL_PRIORITY).addClassAndMethod(this).addSourceLine(
                                    this, getPC());
                    bugReporter.reportBug(bug);
                }
            }
        }
    }
}

4. 将规则加入规则文件中

我们刚才在编写探测器的时候,已经给定了规则的名称CJ_SYSTEMCLASS。现在我们需要将这个规则添加在配置文件中。
配置findbugs.xml:

  
   

配置message.xml:

  
  
    
    Default FindBugs plugin  
    
This plugin contains all of the standard FindBugs detectors.

]]>
代码不能出现System.out

请使用log日志形式打印 ]]>

代码不能出现System.out {1}代码不能出现System.out,请使用log形式输出
不能使用System.out和System.err,请使用log

]]>
影响性能的输出System.out

规则添加完成后,重新打包findbugs.jar:
mvn clean install -Dmaven.test.skip=true

静态代码扫描 (三)——FindBugs 自定义规则入门_第1张图片
这里写图片描述

打包成功后,在可运行版本的findbugs中替换原来的/lib/findbugs.jar
执行findbugs命令,扫描样例文件的class文件,查看运行结果:

这里写图片描述

静态代码扫描 (三)——FindBugs 自定义规则入门_第2张图片
这里写图片描述

在扫描结果中,可以看出确实扫描到了我们设定的问题语句。
使用FindBugs自定义规则成功!

参考文献

IBM.FindBugs,第 1 部分: 提高代码质量
IBM.FindBugs,第 2 部分: 编写自定义检测器
百度文库.用Eclipse自带插件创建自定义findbugs检测器

360Qtest团队公众号

关注公众号,第一时间收到我们推送的新文章~


静态代码扫描 (三)——FindBugs 自定义规则入门_第3张图片
360Qtest二维码.jpg

你可能感兴趣的:(静态代码扫描 (三)——FindBugs 自定义规则入门)