java自定义findbugs规则_静态代码扫描 (三)——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. 明确要定义的规则

我将以一个非常简单的规则举例:代码中避免使用有类似 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 yuanwei

* @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

cfd1feae6a0575fc0a239877808942ef.png

打包成功后,在可运行版本的 findbugs 中替换原来的/lib/findbugs.jar

执行 findbugs 命令,扫描样例文件的 class 文件,查看运行结果:

14f12f219c2cd7c442b5f137e97bcbe5.png

b83a30f44b083f4c232292eb53cd001a.png

在扫描结果中,可以看出确实扫描到了我们设定的问题语句。

使用 FindBugs 自定义规则成功!

参考文献

360Qtest 团队公众号

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值