iOS開發-代碼分析工具之Infer

簡介

https://fbinfer.com/docs/getting-started

Infer 是一個靜態分析工具。Infer可以分析 Objective-CJava 或者 C 代碼,報告潛在的問題。
任何人都可以使用 Infer 檢測應用,這可以將那些嚴重的 bug 扼殺在發佈之前,同時防止應用崩潰和性能低下
在這裏插入圖片描述
關於Infer特性可以去 https://fbinfer.com/ 查看

Infer效率高,規模大,幾分鐘能掃描數千行代碼;支持增量及非增量分析;分解分析,整合輸出結果。infer能將代碼分解,小範圍分析後再將結果整合在一起,兼顧分析的深度和速度。


使用

安裝

我們可通過Home Brew進行快捷安裝。

brew install infer

如果brew很慢,就使用個代理吧。文件挺大的。

或者你可以從github上拉下源碼,自己編譯

https://github.com/facebook/infer/blob/master/INSTALL.md#install-infer-from-source
一般來說這樣要快。

注:文檔中使用了opam也是需要brew install opam

通過brew安裝成功
在這裏插入圖片描述

設置 PATH 變量

如果使用brew install infer 安裝的話請忽略這步。

如果手動下載編譯就需要設置 PATH 變量
我們建議把 Infer 的執行目錄加入到環境變量中,這樣使用起來會簡便一些。當然,你也可以用絕對路徑。本文檔後續默認執行路徑已加入到環境變量中。

你可以使用以下命令設置環境變量。

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

各種使用方式

https://fbinfer.com/docs/hello-world

官方文檔對各種case的使用說明的很詳細。

Object-C文件

對於 OC 單個文件分析,例如下面的 hello.m

#import <Foundation/Foundation.h>

@interface Hello: NSObject
@property NSString* s;
@end

@implementation Hello
NSString* m() {
    Hello* hello = nil;
    return hello.s;
}
@end

命令如下

infer run -- clang -c Hello.m

iOS工程 xcodebuild

  • 創建一個HelloWorldApp工程
  • 寫入有問題的文件hello.hhello.m
#import <Foundation/Foundation.h>

@interface Hello: NSObject
@property NSString* s;
@end

@implementation Hello
NSString* m() {
    Hello* hello = nil;
    return hello->_s;
}
@end

  • cd到工程目錄下,使用infer run
infer run -- xcodebuild -project HCPushSettingViewController.xcodeproj -target HCPushSettingViewController -sdk iphoneos13.2

-sdk版本請用xcodebuild -showsdks查看

然後就生成了infer-out文件
在這裏插入圖片描述

可以從文件中看到問題,同時有各種格式的結果文件,JSON更便於其他系統集成,txt便於我們自己人工查看
在這裏插入圖片描述

出錯時的兼容方法,使用Pod的工程

最健壯的方法是生成一個編譯數據庫,然後通過該數據庫推斷:

xcodebuild <your build options> | tee xcodebuild.log
xcpretty -r json-compilation-database -o compile_commands.json < xcodebuild.log > /dev/null
infer run --skip-analysis-in-path Pods --clang-compilation-db-files-escaped compile_commands.json

HCPushSettingViewController爲例子
在這裏插入圖片描述
先編譯數據database

xcodebuild -workspace HCPushSettingViewController.xcworkspace -scheme HCPushSettingViewController -sdk iphoneos13.2  | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json

然後執行

infer run --skip-analysis-in-path Pods --no-xcpretty --keep-going --clang-compilation-db-files-escaped compile_commands.json

我這裏使用了--no-xcpretty --keep-going,如不需要可以去掉

這裏提示

WARNING: '--clang-compilation-db-files-escaped' is deprecated. Use '--compilation-database-escaped' instead.
//即使用--compilation-database-escaped是新接口

如果直接執行infer run的結果會報錯

** BUILD FAILED **


The following build commands failed:
	Ld build/HCPushSettingViewController.build/Release-iphoneos/HCPushSettingViewController.build/Objects-normal/arm64/HCPushSettingViewController normal arm64
	Ld build/HCPushSettingViewController.build/Release-iphoneos/HCPushSettingViewController.build/Objects-normal/armv7/HCPushSettingViewController normal armv7
(2 failures)
Internal Error:   /usr/local/Cellar/infer/0.17.0/lib/infer/infer/bin/../lib/python/infer.py
  -j 4 --project-root
  /Users/sheng/Desktop/Git/HCPushSettingViewController/Samples --out
  /Users/sheng/Desktop/Git/HCPushSettingViewController/Samples/infer-out --
  xcodebuild -project HCPushSettingViewController.xcodeproj -target
  HCPushSettingViewController -sdk iphoneos13.2:
  exited with code 65
Error backtrace:
Raised at file "string.ml", line 145, characters 16-31
Called from file "string.ml" (inlined), line 149, characters 17-46
Called from file "src/string.ml", line 407, characters 12-33
Called from file "src/string.ml", line 416, characters 11-33
Re-raised at file "base/Die.ml", line 26, characters 8-56
Called from file "integration/Driver.ml", line 171, characters 2-16
Called from file "integration/Driver.ml", line 272, characters 6-409
Called from file "integration/Driver.ml", line 323, characters 2-29
Called from file "base/Utils.ml", line 398, characters 16-20
Called from file "scuba/ScubaLogging.ml", line 66, characters 29-44
Called from file "infer.ml", line 20, characters 2-36
Called from file "base/Utils.ml", line 398, characters 16-20
Called from file "scuba/ScubaLogging.ml", line 66, characters 29-44
Called from file "infer.ml", line 137, characters 8-54

所以這種方法能夠避免這些錯誤,因爲直接infer run也是調用--xcpretty來實現。

官方文檔:https://fbinfer.com/docs/analyzing-apps-or-projects

直接解析database

infer也支持直接解析compile_commands.json文件,其原理與OCLint一致,都是基於Clang

infer --compilation-database compile_commands.json

*** Infer needs a working compilation command to run

add --no-xcpretty

https://github.com/facebook/infer/issues/759

xctool的支持

infer也支持用xctool替換xcodebuild,使用xctool生成一個編譯數據庫後再傳給infer

xctool.sh <your build options> -reporter json-compilation-database:compile_commands.json
infer run --skip-analysis-in-path Pods --clang-compilation-db-files-escaped compile_commands.json

github上有相關資料 https://github.com/facebook/infer/issues/9#issuecomment-280121791


Unknown argument: ‘-index-store-path’

Xcode 9.0-index-store-path添加到構建命令中。在clang中還不支持它。在Build Setting 中搜索index並將Enable Index-While-Building Functionality選項設置爲NO
https://stackoverflow.com/questions/46331918/compilation-error-when-using-xcode-9-0-with-clang-cannot-specify-o-when-genera

增量模式、非增量模式

在第一次運行的時候,兩種模式是一樣的,都會對工程的所有文件進行編譯檢查,產生檢查結果:

增量模式:當已經產生分析結果後(build和infer-out文件夾),再執行編譯命令,即爲增量模式。如有代碼沒有改動,則此次不會有編譯結果產生,如果代碼有新的改動,此次只產生新的編譯結果。這種以增量爲基準的原則叫做增量模式。

非增量模式:在刪除了倆個文件夾(build和infer-out文件夾)的情況下,運行文件,會輸出所有的編譯信息,即此時處於非增量模式。

就是一個緩存刷新的問題,這裏可以刪除文件夾來使用非增量模式,使用--incremental參數打開增量模式,或者使用xcodebuild時,附加clean配置

xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator clean

原理

轉化階段

將源碼轉成infer內部的中間語言。類C語言使用Clang進行編譯,Java語言使用Javac進行編譯,編譯的同時轉成中間語言,輸出到infer-out目錄。

分析階段

分析infer-out目錄下的文件。分析每個方法,如果出現錯誤的話會繼續分析下一個,不會被中斷,但是會記錄出錯位置,最後彙總。

每次運行,infer都會刪除之前的infer-out文件夾,可以通過--incremental參數使用增量模式。

參考文章:

https://www.jianshu.com/p/b81a9f5bcf34
https://www.jianshu.com/p/4667e36aadea

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章