一瓦宜、Infer簡介
Facebook 的 Infer 是一個靜態(tài)分析工具临庇。Infer 可以分析 Objective-C假夺, Java 或者 C 代碼已卷,報告潛在的問題侧蘸。任何人都可以使用 Infer 檢測應(yīng)用讳癌,這可以將那些嚴(yán)重的 bug 扼殺在發(fā)布之前晌坤,同時防止應(yīng)用崩潰和性能低下骤菠。Infer 可檢查 Android 和 Java 代碼中的 NullPointException 和 資源泄露娩怎。除了以上胰柑,Infer 還可發(fā)現(xiàn) iOS 和 C 代碼中的內(nèi)存泄露。
Infer 已經(jīng)成為 Facebook 開發(fā)流程的一個環(huán)節(jié)崩瓤,包括 Facebook Android 和 iOS 主客戶端,F(xiàn)acebook Messenger颖系, Instagram 在內(nèi)的嘁扼,以及其他影響億萬用戶的手機(jī)應(yīng)用黔攒,每次代碼變更趁啸,都要經(jīng)過 Infer 的檢測。
二督惰、Infer安裝
1不傅、Homebrew 安裝
brew install infer
如果安裝太久,或者安裝失敗赏胚,也可以使用下面的安裝包的方式進(jìn)行安裝
2访娶、安裝包安裝
1)GitHub下載安裝包:https://github.com/facebook/infer/releases 選擇對應(yīng)的版本,進(jìn)行下載觉阅。
2)下載后進(jìn)行解壓崖疤,解壓后會有一個 infer-osx-v1.0.0
目錄戳晌,v1.0.0是對應(yīng)的版本號豪嚎。主執(zhí)行目錄是infer-osx-v1.0.0/lib/infer/infer/bin/
3)設(shè)置PATH變量糯耍。建議把 Infer 的執(zhí)行目錄加入到環(huán)境變量中扭粱,這樣使用起來會簡便一些博其。當(dāng)然儡率,你也可以用絕對路徑眉孩。本文檔后續(xù)默認(rèn)執(zhí)行路徑已加入到環(huán)境變量中死遭。
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)執(zhí)行 infer --version
钠署,如果輸出對應(yīng)的版本狸棍,則說明安裝成功
三傍菇、Infer的使用
1咐低、Infer基本用法
我們可以新建一個測試工程InferTest
损痰,并在 ViewController.m
中辽社,寫上一段代碼:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = @"1";
}
@end
首先用cd命令進(jìn)入InferTest
目錄,然后運(yùn)行以下命令進(jìn)行編譯:
infer -- xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator
執(zhí)行結(jié)束后,終端上面會展示錯誤信息,在項目所在目錄下也會多出build
和infer-out
文件夾,其中report.txt
中的信息和終端上的信息一樣
可以看出阅懦,我們的 ViewController.m 代碼里有1個問題怕午,將代碼修改如下:
NSString *str = @"1";
NSLog(@"str = %@",str);
先手動刪除build
文件夾(清除編譯信息), 再次執(zhí)行上述命令郁惜,重新編譯:
infer -- xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator
執(zhí)行結(jié)果:
恭喜??????,問題已經(jīng)消除甲锡,以上就是infer的基本用法缤沦。
2、可能出現(xiàn)的問題
1)出現(xiàn)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)在兩次執(zhí)行編譯命令的過程中妓肢,發(fā)現(xiàn)在沒有對代碼做任何更改的時候(bug還在)色徘,報出BUILD SUCCEEDED的提示:
根據(jù)提示可以看到,此次build并沒有分析任何文件操禀。原因涉及到增量分析,默認(rèn)編譯的是有改變的代碼横腿,下一小節(jié)會詳細(xì)介紹颓屑。
3、增量模式和非增量模式
第一次運(yùn)行的時候耿焊,兩種模式是一樣的揪惦,都會對工程的所有文件進(jìn)行編譯檢查,產(chǎn)生檢查結(jié)果:
增量模式:當(dāng)已經(jīng)產(chǎn)生分析結(jié)果后(build和infer-out文件夾)罗侯,再執(zhí)行編譯命令器腋,即為增量模式。如有代碼沒有改動钩杰,則此次不會有編譯結(jié)果產(chǎn)生纫塌,如果代碼有新的改動,此次只產(chǎn)生新的編譯結(jié)果讲弄。這種以增量為基準(zhǔn)的原則叫做增量模式措左。
非增量模式:在刪除了倆個文件夾的情況下,運(yùn)行文件避除,會輸出所有的編譯信息怎披,即此時處于非增量模式。
增量模式轉(zhuǎn)化為非增量模式:
第1種瓶摆、直接刪除文件夾(build和infer-out文件夾)
第2種凉逛、先使用xcodebuild clean 清除一下對應(yīng)的 target 工程,之后再重新編譯分析
xcodebuild -target InferTest -configuration Debug -sdk iphonesimulator clean
4群井、分析帶cocoapods的項目
1)執(zhí)行命令
先識別 /***.xcworkspace
状飞,再識別 scheme
infer -- xcodebuild -workspace InferTest.xcworkspace -scheme InferTest -configuration Debug -sdk iphonesimulator
這種方法會分享所有的代碼,而當(dāng)我們在項目中使用了很多第三方的時候,其實(shí)我們只想讓Infer分析我們的代碼昔瞧,而不想分析第三方的代碼指蚁,不然分析報告中會有很多第三方的issue,看著混亂自晰,這時我們可以用命令行過濾掉關(guān)于不想分析的文件凝化。比如用到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 后面跟的是一個忽略文件或者文件夾的路徑數(shù)組搓劫。
方法二
在工程目錄下新建 .inferconfig
文件, 內(nèi)容如圖, 可以過濾掉Pods文件夾下的第三方庫, skip-analysis-in-path是一個數(shù)組, 想要過濾其他文件, 只需要增加路徑即可混巧。
1枪向、in-path 后面跟的是一個忽略文件或者文件夾的路徑數(shù)組。
2咧党、["Pods"] 代表過濾所有的 Pods 文件
3秘蛔、["Pods/AFNetworking","Pods/Masonry"] 代表過濾 AFNetworking、Masonry 三方庫
4傍衡、也可以寫個腳本對解析出來的文件進(jìn)行二次拆分深员,按組件模塊、錯誤和警告劃分
四蛙埂、Infer工作流程
不管是分析哪種語言倦畅,Infer 運(yùn)行時,分為兩個主要階段:捕獲階段绣的、分析階段
1叠赐、捕獲階段
Infer 捕獲編譯命令,將文件翻譯成 Infer 內(nèi)部的中間語言屡江。
這種翻譯和編譯類似芭概,Infer 從編譯過程獲取信息,并進(jìn)行翻譯盼理。這就是我們調(diào)用 Infer 時帶上一個編譯命令的原因了谈山,比如: infer -- clang -c file.c, infer -- javac File.java。結(jié)果就是文件照常編譯宏怔,同時被 Infer 翻譯成中間語言奏路,留作第二階段處理。特別注意的就是臊诊,如果沒有文件被編譯鸽粉,那么也沒有任何文件會被分析。
Infer 把中間文件存儲在結(jié)果文件夾中抓艳,一般來說焰宣,這個文件夾會在運(yùn)行 infer 的目錄下創(chuàng)建嗡呼,命名是 infer-out/恋日。當(dāng)然吃挑,你也可以通過 -o 選項來自定義文件夾名字
2票顾、分析階段
在分析階段,Infer 分析 infer-out/ 下的所有文件。分析時,會單獨(dú)分析每個方法和函數(shù)对供。
在分析一個函數(shù)的時候,如果發(fā)現(xiàn)錯誤氛濒,將會停止分析产场,但這不影響其他函數(shù)的繼續(xù)分析。所以你在檢查問題的時候舞竿,修復(fù)輸出的錯誤之后京景,需要繼續(xù)運(yùn)行 Infer 進(jìn)行檢查,知道確認(rèn)所有問題都已經(jīng)修復(fù)骗奖。
錯誤除了會顯示在標(biāo)準(zhǔn)輸出之外确徙,還會輸出到文件 infer-out/bug.txt 中,我們過濾這些問題重归,僅顯示最有可能存在的米愿。在結(jié)果文件夾中(infer-out),同時還有一個 csv 文件 report.csv鼻吮,這里包含了所有 Infer 產(chǎn)生的信息,包括:錯誤较鼓,警告和信息椎木。
五、常見掃描錯誤
1博烂、DIRECT_ATOMIC_PROPERTY_ACCESS香椎。
在代碼中使用了使用了一個atomic的成員變量,infer建議我們將atomic修改為nonatomic禽篱。由于OC中畜伐,屬性會被默認(rèn)設(shè)置為atomic屬性,我們需要顯示將屬性聲明為nonatomic躺率。關(guān)于atomic與nonatomic的區(qū)別可以參見文章https://my.oschina.net/linxiaoxi1993/blog/381332
該警告占了大概800個玛界。在代碼中主動設(shè)置成員變量的nonatomic屬性,即可去除警告
2悼吱、ASSIGN_POINTER_WARNING
由于在mrc時代慎框,沒有weak指針,所以一些view的屬性聲明是后添、unsafe__unretain_的形式笨枯,在arc中,這個屬性被判斷為assign,需要將其修改為weak或者strong
3馅精、NULL_DEREFERENCE
空指針的情況严嗜。根據(jù)具體代碼的不同,出現(xiàn)空指針的情況也有所不同洲敢。
1)傳參為0的情況下漫玄。例如代碼中,在調(diào)用showAlertViewA()時沦疾,將tag傳參為0,infer檢測此處傳0称近,判斷為一個NULL空指針,所以爆出警告哮塞。這里可以理解為誤報刨秆,不會出現(xiàn)問題。
2)通過malloc,calloc,realloc等函數(shù)申請內(nèi)存忆畅,當(dāng)內(nèi)存不足時衡未,有可能會在該函數(shù)中返回NULL,如果沒有做NULL的判斷家凯,則警告
3)在創(chuàng)建NSArray或者NSDictionary時缓醋,傳入的參數(shù)有可能會nil。由于NSArray與NSDictionary不接受空指針绊诲,所以在對其addObject或者setObject:forKey: 時需要進(jìn)行判斷一下是否為nil送粱。
4、IVAR_NOT_NULL_CHECKED
在代碼中調(diào)用block掂之,運(yùn)行代碼時抗俄,沒有做判空處理。即需要改動為世舰,
if(block){block()}
5动雹、BAD_POINTER_COMPARISON
Implicitly checking whether NSNumber pointer is nil。沒有判斷一個NSNumber類型的對象是不是空跟压?此處應(yīng)該是誤報胰蝠。
6、TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION
代碼中使用了cookie的value震蒋∪兹可以理解為誤報
7、PARAMETER_NOT_NULL_CHECKED
傳參時沒有判斷是否為null喷好,加一次判斷就可以了
8翔横、STRONG_DELEGATE_WARNING
將一個delegate屬性設(shè)置為strong的類型。
9梗搅、PREMATURE_NIL_TERMINATION_ARGUMENT
沒有判斷是否為空
10禾唁、REGISTERED_OBSERVER_BEING_DEALLOCATED
創(chuàng)建一個對象后效览,監(jiān)聽了某些通知,但是沒有在dealloc中釋放該通知荡短。項目中出現(xiàn)這種問題的類丐枉,基本都是單例,不會被銷毀掘托。
11瘦锹、MEMORY_LEAK
內(nèi)存泄露。項目代碼全面啟動了ARC進(jìn)行內(nèi)存管理闪盔,在OC層沒有掃描出內(nèi)存泄露弯院。目前掃描出的內(nèi)存泄露問題都是使用了malloc或者ralloc等c語言內(nèi)存申請函數(shù),在函數(shù)提前return前沒有及時free泪掀。
參考鏈接:
infer官網(wǎng):https://fbinfer.com/docs/getting-started.html
infer中文網(wǎng)站:https://infer.liaohuqiu.net
iOS infer靜態(tài)分析工具使用:http://www.reibang.com/p/fd1923cc87eb
iOS-App接入infer靜態(tài)分析掃描工具:http://www.reibang.com/p/52f61498e2b2
iOS開發(fā)之使用 infer靜態(tài)代碼掃描工具:https://www.cnblogs.com/ZachRobin/p/11280499.html
xcode-select --install 解決方案:https://blog.csdn.net/lucky9322/article/details/79036877