当前位置: 首页 > 技术与资源 > 技术分享 > 正文

Facebook静态代码分析工具Infer探索

2016-01-08 11:28:19

作者:暨景书新炬网络高级技术专家。


随着IT系统的广泛应用,补丁、需求大量变更,版本快速迭代,需要频繁的进行发布,发布管理质量不高,导致故障频繁。如何在上线采取有效措施,将一些潜在的bug扼杀在版本发布之前,优化代码,防止应用的崩溃和性能低下问题,值得我们去探索。


目前行业主要是通过静态代码分析方式,在无需运行被测代码前提下,在构建代码过程中帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省软件开发和测试成本。静态代码分析可以分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性,找出代码隐藏的错误和缺陷,如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针引用等。


Infer 是Facebook 今年刚开源一款静态分析工具。Infer 可以分析 Objective-C, Java 或者 C 代码,重点作用于分析APP(Android/iOS)项目,报告潜在的问题。Infer 已经成为 Facebook 开发流程的一个环节,包括 Facebook Android 和 iOS 主客户端,Facebook Messenger, Instagram 在内的,以及其他影响亿万用户的手机应用,每次代码变更,都要经过 Infer 的检测。


先介绍infer 相比其它静态分析工具有什么优点:


1、  是一款开源静态的代码分析工具;


2、  效率高,规模大,几分钟可以扫描数千行代码;


3、  支持增量及非增量分析;


4、  分解分析,整合输出结果。Infer能将代码分解,小范围分析后再将结果整合在一起,兼顾分析的深度和速度。


Infer捕捉的bug类型:


1.   Java中捕捉的bug类型


Resource leak
Null dereference

2.   C/OC中捕捉的bug类型


Resource leak
Memory leak
Null dereference
Premature nil termination argument

3.   只在 OC中捕捉的bug类型


Retain cycle
Parameter not null checked
Ivar not null checked

Infer 官方网站主要是介绍了如何分析APP(Android/iOS)项目及单个java文件,并没有介绍针对整个JAVA 项目进行分析。大家都知道,日常中系统都是以多个java文件组成项目方式存在,本次将重点介绍如何利用Infer分析JAVA/Android 项目及在部署infer 时将会碰到一些问题,以避免大家在研究infer 走更多的弯路。


一.  Infer 处理流程


暨景书 - Facebook静态代码分析工具Infer探索1

Infer 将 Objective-C(ios)/Java/C开发程序,通过编绎器分析出相应bugs 信息,目前infer 支持的编译器有如下几种:


 编号 编译器名称 备注
1 javac 分析单个文件
2 clang 分析单个文件
3 make 分析C/C++项目
4 Maven 命令支持,官方无相关资料介绍,测试过无法分析java  项目,有报错现象,
[ERROR] Error during capture phase, exiting
此错误没有提示具体原因,待官方反馈解决
参考:
https://github.com/facebook/infer/issues/182
5 Ant 命令支持,官方无相关资料介绍,亲测出现Maven同样的错误待官方反馈解决
6 Gradle 主要用来分析android/JAVA项目
7 Xcodebuild 分析iOS项目

不管你使用哪一种编译器,infer 分析都会经过两种阶段:


1.  捕获阶段: Infer 捕获编译命令(上面介绍的编译器命令),将文件翻译成 Infer 内部的中间语言。


2.  分析阶段:Infer 将分析bugs结果输出到不同格式文件中,如csv、txt、json 方便对分析结果进行加工分析。


二.  Infer安装与部署及分析


1.  环境要求


操作系统: Ubuntu 14.04 64位,并且安装好对应的桌面, 不要使用redhat 操作系统(多次测试出现infer有一些包出现无法安装现象)


Python版本:大于等于2.7


JAVA环境: JDK 1.7,不要使用JDK 1.8(测试不支持)


严格按上面要求环境下安装infer ,否则只能哈哈了,惨痛的教训


2.  环境安装


官方提供了预编译好的Infer工具,直接下载使用即可,测试过官方提供的最新编译好的版本0.4.0无法正常使用(无法解压)。建议自己通过下载最新源码方式,进行手动编译后,再使用。


1)  安装OCaml依赖:


sudo apt-get update  #更新ubt 安装源
sudo apt-get upgrade
sudo apt-get install git openjdk-7-jdk m4 zlib1g-dev python-software-properties build-essential libgmp-dev libmpfr-dev libmpc-dev unzip  #更新OCaml依耐包
wget https://github.com/ocaml/opam/releases/download/1.2.2/opam-1.2.2-x86_64-Linux -O opam    #下载opam   
chmod +x opam
./opam init --comp=4.01.0     # 然后在最后一个问题处按下“y”
eval `./opam config env`
./opam install sawja.1.5 atdgen.1.5.0 javalib.2.3 extlib.1.5.4    # 然后在问题处按下“y”

2)  下载Infer的仓库


git clone https://github.com/facebook/infer.git
cd infer
make -C infer java
export PATH=`pwd`/infer/bin:$PATH

3)  将infer加入环境变量中


cd infer-linux64-v0.4.0 &&
echo "export PATH=\"\$PATH:`pwd`/infer/infer/bin\"" \ >> ~/.bash_profile &&
source ~/.bash_profile

4)  Infer验证


暨景书 - Facebook静态代码分析工具Infer探索2

分析单个java 文件例子, 报告输出对应java 文件存在空指针错误


暨景书 - Facebook静态代码分析工具Infer探索3

报表结果输出


暨景书 - Facebook静态代码分析工具Infer探索4

3.  Android项目分析


1) 安装gradle


http://gradle.org/gradle-download/gradle-2.2.1-all.zip  #对应系统版本
unzip gradle-2.2.1-all.zip

配置环境变量,vi ~/.bashrc添加


export PATH=/opt/gradle-2.2.1/bin:$PATH
保存后执行source ~/.bashrc

2) 安装及配置android sdk


下载android-sdk_r24.3.3-linux.tgz


https://developer.android.com/sdk/index.html
tar -xzvf android-sdk_r24.3.3-linux.tgz
chmod -R 755 android-sdk_r24.3.3-linux
cd /opt/sdk/android-sdk-linux/tools/./android

打开android sdk 图形界面,更新Android SDK Build-tools 、 Android Support Repository、Android SDK Platform-tools 23.0.1、Android 5.1.1(API 22)-SDK Platform 22----一定安装对应的SDK更新,否则无法正常使用。


3) 安装依耐包


apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0
apt-get install lib32stdc++6

4) 分析android 项目


在infer 提供的例子里面(/opt/infer/infer/examples/android_hello)新建一个local.properties文件并设定本地 SDK 路径


sdk.dir=/opt/sdk/android-sdk-linux

在infer 提供的例子里面(/opt/infer/infer/examples/android_hello)执行:


infer -- ./gradlew build

将分析出andorid 项目bugs信息


4.  JAVA项目分析


1)  安装gradle同上介绍内容


2)  新建一个JAVA 项目(如testjava):


在项目主目录下,创建以下子目录:mkdir -p src/main/java/hello


└── src
    └── main
        └── java
            └── hello

在src/main/java/hello目录中,你可以创建任何Java类。为简单起见并且为了与指南的其余部分保持一致,我们建议创建两个雷HelloWorld.java和Greeter.java


src/main/java/hello/HelloWorld.java的源代码:


package hello;
public class HelloWorld {
  public static void main(String[] args) {
    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

src/main/java/hello/Greeter.java的源代码:


package hello;
public class Greeter {
  public String sayHello() {
    return "Hello world!";
  }
}

3)  在java 项目下,新建gradle 编译器配置文件build.gradle


apply plugin: 'java'

4)  分析java 项目


gradle clean  #清除当前项目编译任务
infer -- gradle build

当出现如下信息时表示处理成功


Starting analysis (Infer version git-401109b4eb9d54ef8831ee953a3436ec3e2bb72e)
Analysis finished in 0.047985s
src/main/java/hello/Greeter.java:6: error: NULL_DEREFERENCE
  object s last assigned on line 5 could be null and is dereferenced at line 6
src/main/java/hello/HelloWorld.java:12: error: NULL_DEREFERENCE
  object s last assigned on line 11 could be null and is dereferenced at line 12

从上面可以看出利infer 可以经松分析出代码项目bugs信息,为代码优化指明了方向。 有了infer 这种工具,我们就可以与其它持续化部署工具Jenkins容器结合在一起,组成可持续集成和自动部署自动化部署整体解决方案。当然如果使用Docker容器来管理这些工具,那自动化部署方案将更加完美了。


暨景书 - Facebook静态代码分析工具Infer探索5

上一篇:传统企业IT架构如何互联网化
下一篇:软件测试经验分享