美文网首页
iOS静态分析:Infer的使用

iOS静态分析:Infer的使用

作者: 张聪_2048 | 来源:发表于2020-12-01 14:01 被阅读0次

    一、Infer简介

    Facebook 的 Infer 是一个静态分析工具。Infer 可以分析 Objective-C, Java 或者 C 代码,报告潜在的问题。任何人都可以使用 Infer 检测应用,这可以将那些严重的 bug 扼杀在发布之前,同时防止应用崩溃和性能低下。Infer 可检查 Android 和 Java 代码中的 NullPointException 和 资源泄露。除了以上,Infer 还可发现 iOS 和 C 代码中的内存泄露。

    Infer 已经成为 Facebook 开发流程的一个环节,包括 Facebook Android 和 iOS 主客户端,Facebook Messenger, Instagram 在内的,以及其他影响亿万用户的手机应用,每次代码变更,都要经过 Infer 的检测。

    Infer简介.png

    二、Infer安装

    1、Homebrew 安装

    brew install infer
    

    如果安装太久,或者安装失败,也可以使用下面的安装包的方式进行安装

    2、安装包安装

    1)GitHub下载安装包:https://github.com/facebook/infer/releases 选择对应的版本,进行下载。

    2)下载后进行解压,解压后会有一个 infer-osx-v1.0.0 目录,v1.0.0是对应的版本号。主执行目录是infer-osx-v1.0.0/lib/infer/infer/bin/

    3)设置PATH变量。建议把 Infer 的执行目录加入到环境变量中,这样使用起来会简便一些。当然,你也可以用绝对路径。本文档后续默认执行路径已加入到环境变量中。

    open ~/.bash_profile
    export PATH="${PATH}:/Users/zjh48/Documents/infer-osx-v1.0.0/lib/infer/infer/bin"
    source ~/.bash_profile
    

    注意 export PATH="${PATH}:/Users/zjh48/Documents/infer-osx-v1.0.0/lib/infer/infer/bin" 这个需要写成自己的路径

    4)执行 infer --version,如果输出对应的版本,则说明安装成功

    三、Infer的使用

    1、Infer基本用法

    我们可以新建一个测试工程InferTest,并在 ViewController.m 中,写上一段代码:

    #import "ViewController.h"
    
    @interface ViewController ()
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSString *str = @"1";
    }
    
    @end
    

    首先用cd命令进入InferTest目录,然后运行以下命令进行编译:

    infer -- xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator
    

    执行结束后,终端上面会展示错误信息,在项目所在目录下也会多出buildinfer-out文件夹,其中report.txt中的信息和终端上的信息一样

    Infer编译分析出问题.png

    可以看出,我们的 ViewController.m 代码里有1个问题,将代码修改如下:

    NSString *str = @"1";
    NSLog(@"str = %@",str);
    

    先手动删除build文件夹(清除编译信息), 再次执行上述命令,重新编译:

    infer -- xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator
    

    执行结果:

    Infer编译分析没有问题.png

    恭喜🎉🎉🎉,问题已经消除,以上就是infer的基本用法。

    2、可能出现的问题

    1)出现xcode-select: error

    xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
    

    这种情况是这种情况是xcodebuild的路径不正确。将路径切换到Xcode的目录下,如下:

    sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
    
    

    2)在两次执行编译命令的过程中,发现在没有对代码做任何更改的时候(bug还在),报出BUILD SUCCEEDED的提示:

    Infer编译没变化.png

    根据提示可以看到,此次build并没有分析任何文件。原因涉及到增量分析,默认编译的是有改变的代码,下一小节会详细介绍。

    3、增量模式和非增量模式

    第一次运行的时候,两种模式是一样的,都会对工程的所有文件进行编译检查,产生检查结果:
    增量模式:当已经产生分析结果后(build和infer-out文件夹),再执行编译命令,即为增量模式。如有代码没有改动,则此次不会有编译结果产生,如果代码有新的改动,此次只产生新的编译结果。这种以增量为基准的原则叫做增量模式。
    非增量模式:在删除了俩个文件夹的情况下,运行文件,会输出所有的编译信息,即此时处于非增量模式。

    增量模式转化为非增量模式:

    第1种、直接删除文件夹(build和infer-out文件夹)

    第2种、先使用xcodebuild clean 清除一下对应的 target 工程,之后再重新编译分析

    xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator clean
    

    4、分析带cocoapods的项目

    1)执行命令

    先识别 /***.xcworkspace,再识别 scheme

    infer -- xcodebuild -workspace InferTest.xcworkspace -scheme InferTest -configuration Debug -sdk iphonesimulator
    

    这种方法会分享所有的代码,而当我们在项目中使用了很多第三方的时候,其实我们只想让Infer分析我们的代码,而不想分析第三方的代码,不然分析报告中会有很多第三方的issue,看着混乱,这时我们可以用命令行过滤掉关于不想分析的文件。比如用到cocoapods的项目,我们想过滤掉Pods引入的第三方库。

    2)过滤三方库

    方法一

    在命令行里添加过滤条件:INFER_ARGS="--skip-clang-analysis-in-path^[\"Pods\"]"

    INFER_ARGS="--skip-clang-analysis-in-path^[\"Pods\"]" infer -- xcodebuild -workspace InferTest.xcworkspace -scheme InferTest -configuration Debug -sdk iphonesimulator
    

    in-path 后面跟的是一个忽略文件或者文件夹的路径数组。

    方法二

    在工程目录下新建 .inferconfig 文件, 内容如图, 可以过滤掉Pods文件夹下的第三方库, skip-analysis-in-path是一个数组, 想要过滤其他文件, 只需要增加路径即可。

    inferconfig配置文件.png

    1、in-path 后面跟的是一个忽略文件或者文件夹的路径数组。
    2、["Pods"] 代表过滤所有的 Pods 文件
    3、["Pods/AFNetworking","Pods/Masonry"] 代表过滤 AFNetworking、Masonry 三方库
    4、也可以写个脚本对解析出来的文件进行二次拆分,按组件模块、错误和警告划分

    四、Infer工作流程

    不管是分析哪种语言,Infer 运行时,分为两个主要阶段:捕获阶段、分析阶段

    1、捕获阶段

    Infer 捕获编译命令,将文件翻译成 Infer 内部的中间语言。

    这种翻译和编译类似,Infer 从编译过程获取信息,并进行翻译。这就是我们调用 Infer 时带上一个编译命令的原因了,比如: infer -- clang -c file.c, infer -- javac File.java。结果就是文件照常编译,同时被 Infer 翻译成中间语言,留作第二阶段处理。特别注意的就是,如果没有文件被编译,那么也没有任何文件会被分析。

    Infer 把中间文件存储在结果文件夹中,一般来说,这个文件夹会在运行 infer 的目录下创建,命名是 infer-out/。当然,你也可以通过 -o 选项来自定义文件夹名字

    2、分析阶段

    在分析阶段,Infer 分析 infer-out/ 下的所有文件。分析时,会单独分析每个方法和函数。

    在分析一个函数的时候,如果发现错误,将会停止分析,但这不影响其他函数的继续分析。所以你在检查问题的时候,修复输出的错误之后,需要继续运行 Infer 进行检查,知道确认所有问题都已经修复。

    错误除了会显示在标准输出之外,还会输出到文件 infer-out/bug.txt 中,我们过滤这些问题,仅显示最有可能存在的。在结果文件夹中(infer-out),同时还有一个 csv 文件 report.csv,这里包含了所有 Infer 产生的信息,包括:错误,警告和信息。

    Infer 的工作流程图.png

    五、常见扫描错误

    1、DIRECT_ATOMIC_PROPERTY_ACCESS。

    在代码中使用了使用了一个atomic的成员变量,infer建议我们将atomic修改为nonatomic。由于OC中,属性会被默认设置为atomic属性,我们需要显示将属性声明为nonatomic。关于atomic与nonatomic的区别可以参见文章https://my.oschina.net/linxiaoxi1993/blog/381332
    该警告占了大概800个。在代码中主动设置成员变量的nonatomic属性,即可去除警告

    2、ASSIGN_POINTER_WARNING

    由于在mrc时代,没有weak指针,所以一些view的属性声明是、unsafe__unretain_的形式,在arc中,这个属性被判断为assign,需要将其修改为weak或者strong

    3、NULL_DEREFERENCE

    空指针的情况。根据具体代码的不同,出现空指针的情况也有所不同。
    1)传参为0的情况下。例如代码中,在调用showAlertViewA()时,将tag传参为0,infer检测此处传0,判断为一个NULL空指针,所以爆出警告。这里可以理解为误报,不会出现问题。
    2)通过malloc,calloc,realloc等函数申请内存,当内存不足时,有可能会在该函数中返回NULL,如果没有做NULL的判断,则警告
    3)在创建NSArray或者NSDictionary时,传入的参数有可能会nil。由于NSArray与NSDictionary不接受空指针,所以在对其addObject或者setObject:forKey: 时需要进行判断一下是否为nil。

    4、IVAR_NOT_NULL_CHECKED

    在代码中调用block,运行代码时,没有做判空处理。即需要改动为,
    if(block){block()}

    5、BAD_POINTER_COMPARISON

    Implicitly checking whether NSNumber pointer is nil。没有判断一个NSNumber类型的对象是不是空?此处应该是误报。

    6、TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION

    代码中使用了cookie的value。可以理解为误报

    7、PARAMETER_NOT_NULL_CHECKED

    传参时没有判断是否为null,加一次判断就可以了

    8、STRONG_DELEGATE_WARNING

    将一个delegate属性设置为strong的类型。

    9、PREMATURE_NIL_TERMINATION_ARGUMENT

    没有判断是否为空

    10、REGISTERED_OBSERVER_BEING_DEALLOCATED

    创建一个对象后,监听了某些通知,但是没有在dealloc中释放该通知。项目中出现这种问题的类,基本都是单例,不会被销毁。

    11、MEMORY_LEAK

    内存泄露。项目代码全面启动了ARC进行内存管理,在OC层没有扫描出内存泄露。目前扫描出的内存泄露问题都是使用了malloc或者ralloc等c语言内存申请函数,在函数提前return前没有及时free。



    参考链接:
    infer官网:https://fbinfer.com/docs/getting-started.html
    infer中文网站:https://infer.liaohuqiu.net
    iOS infer静态分析工具使用:https://www.jianshu.com/p/fd1923cc87eb
    iOS-App接入infer静态分析扫描工具:https://www.jianshu.com/p/52f61498e2b2
    iOS开发之使用 infer静态代码扫描工具:https://www.cnblogs.com/ZachRobin/p/11280499.html
    xcode-select --install 解决方案:https://blog.csdn.net/lucky9322/article/details/79036877

    相关文章

      网友评论

          本文标题:iOS静态分析:Infer的使用

          本文链接:https://www.haomeiwen.com/subject/nnkswktx.html