小小西 發表於 2019-8-1 09:18:00

iOS开发之使用 infer静态代码扫描工具

<p>  infer是Facebook&nbsp;的&nbsp;Infer&nbsp;是一个静态分析工具。可以分析&nbsp;Objective-C,&nbsp;Java&nbsp;或者&nbsp;C&nbsp;代码,报告潜在的问题。</p>
<p>  任何人都可以使用 infer 检测应用,可以将严重的 bug 扼杀在发布之前,同时防止应用崩溃和性能低下。</p>
<p>  <img src="https://img2018.cnblogs.com/blog/857497/201908/857497-20190801054347120-1549571806.png"></p>
<p>  infer 可以检查 Java 和 Android 中的 NullPointException 和资源泄漏。</p>
<p>  除了以上,infer 还可以检测 iOS 和 C 代码的内存泄漏!</p>
<p>  应用范围:</p>
<p>    包括 Facebook Android 和 iOS 主客户端,Facebook Messenger, Instagram 在内的,以及其他影响亿万用户的手机应用,每次代码变更,都要经过 Infer 的检测。&nbsp;</p>
<p>  infer 优点:</p>
<p>    1、效率高、规模大,几分钟能扫描上千行代码;</p>
<p>    2、支持增量及非增量分析;</p>
<p>    3、分解分析,输出整合结果(infer能将代码分解,小范围分析后再将结果整合在一起,兼顾分 析的深度和速度)&nbsp;;</p>
<p>  在 iOS 和 C 中,infer 能捕捉的 bug 类型有:</p>
<p>    1、资源泄漏;</p>
<p>    2、内存泄漏;</p>
<p>    3、null 引用;</p>
<p>    4、Premature nil termination argument&nbsp;</p>
<p>  只在 OC 中捕捉的 bug 类型有:</p>
<p>    1、循环引用(Retain cycle);</p>
<p>    2、参数非空检查;</p>
<p>    3、实例变量非空检查;</p>
<p>  Github 地址:https://github.com/facebook/infer</p>
<p>  配置 infer 安装:</p>
<p>    1、homebrew 安装:</p>
<p>    <em><span style="color: rgba(136, 136, 136, 1)">brew install infer</span></em></p>
<p>    如果安装报错,可根据提示信息更新 brew:<em><span style="color: rgba(136, 136, 136, 1)">brew update</span></em></p>
<p>    2、在官网下载安装包进行安装:  </p>
<p>    安装成功之后,输入 infer --version 来查看版本号:</p>
<p>    <img src="https://img2018.cnblogs.com/blog/857497/201908/857497-20190801054145857-852847114.png"></p>
<p>  配置到环境变量:&nbsp;</p>
<p><span style="color: rgba(136, 136, 136, 1)">    <code class="hljs ruby">echo <span class="hljs-string">"export PATH=\"\$PATH:pwd/infer/infer/bin\"" \ <span class="hljs-meta">&gt;&gt; ~<span class="hljs-regexp">/.bash_profile &amp;&amp;source ~/.bash_profile</span></span></span></code></span></p>
<p>  </p>
<p>  使用 infer 工具进行代码分析:</p>
<p>  分析单个文件:</p>
<p>  分析工程:</p>
<p><span style="color: rgba(128, 128, 128, 1)">    infer <span style="color: rgba(255, 0, 0, 1)">run</span> <span class="nt">-- xcodebuild <span class="nt">-target &lt;target name&gt; <span class="nt">-configuration &lt;build configuration&gt; <span class="nt">-sdk iphonesimulator</span></span></span></span></span></p>
<p>  如果是 Pod 工程,执行:</p>
<p>    <span class="s1" style="color: rgba(136, 136, 136, 1)"><span style="color: rgba(255, 0, 0, 1)">infer run -- xcodebuild -workspace</span> AVRecorder.<span style="color: rgba(255, 0, 0, 1)">xcworkspace</span> -scheme AVRecorder -configuration Debug -sdk iphonesimulator</span></p>
<p>&nbsp;</p>
<p>  ps:被这个 infer run 命令给坑了,按照其他人博客上的命令:<span style="color: rgba(128, 128, 128, 1)">infer -- xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator&nbsp;</span></p>
<p>&nbsp;  出现错误:</p>
<div class="cnblogs_code">
<pre>** BUILD FAILED **<span style="color: rgba(0, 0, 0, 1)">

Internal Error:   </span>/usr/local/Cellar/infer/<span style="color: rgba(128, 0, 128, 1)">0.15</span>.<span style="color: rgba(128, 0, 128, 1)">0</span>/lib/infer/infer/bin/../lib/python/<span style="color: rgba(0, 0, 0, 1)">infer.py
</span>-j <span style="color: rgba(128, 0, 128, 1)">8</span> --project-<span style="color: rgba(0, 0, 0, 1)">root
</span>/Users/zhangtibin/Downloads/infer-master/examples/ios_hello --<span style="color: rgba(0, 0, 255, 1)">out</span>
/Users/zhangtibin/Downloads/infer-master/examples/ios_hello/infer-<span style="color: rgba(0, 0, 255, 1)">out</span> --<span style="color: rgba(0, 0, 0, 1)">
xcodebuild </span>-project HelloWorldApp.xcodeproj -<span style="color: rgba(0, 0, 0, 1)">scheme HelloWorldApp
</span>-<span style="color: rgba(0, 0, 0, 1)">configuration Debug:
exited with code </span><span style="color: rgba(128, 0, 128, 1)">65</span><span style="color: rgba(0, 0, 0, 1)">
Error backtrace:
Raised at file </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">base/Die.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span> (inlined), line <span style="color: rgba(128, 0, 128, 1)">25</span>, characters <span style="color: rgba(128, 0, 128, 1)">6</span>-<span style="color: rgba(128, 0, 128, 1)">36</span><span style="color: rgba(0, 0, 0, 1)">
Called </span><span style="color: rgba(0, 0, 255, 1)">from</span> file <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">base/Logging.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span>, line <span style="color: rgba(128, 0, 128, 1)">314</span>, characters <span style="color: rgba(128, 0, 128, 1)">58</span>-<span style="color: rgba(128, 0, 128, 1)">80</span><span style="color: rgba(0, 0, 0, 1)">
Called </span><span style="color: rgba(0, 0, 255, 1)">from</span> file <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">integration/Driver.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span>, line <span style="color: rgba(128, 0, 128, 1)">159</span>, characters <span style="color: rgba(128, 0, 128, 1)">2</span>-<span style="color: rgba(128, 0, 128, 1)">16</span><span style="color: rgba(0, 0, 0, 1)">
Called </span><span style="color: rgba(0, 0, 255, 1)">from</span> file <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">integration/Driver.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span>, line <span style="color: rgba(128, 0, 128, 1)">280</span>, characters <span style="color: rgba(128, 0, 128, 1)">6</span>-<span style="color: rgba(128, 0, 128, 1)">420</span><span style="color: rgba(0, 0, 0, 1)">
Called </span><span style="color: rgba(0, 0, 255, 1)">from</span> file <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">infer.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span>, line <span style="color: rgba(128, 0, 128, 1)">20</span>, characters <span style="color: rgba(128, 0, 128, 1)">2</span>-<span style="color: rgba(128, 0, 128, 1)">36</span><span style="color: rgba(0, 0, 0, 1)">
Called </span><span style="color: rgba(0, 0, 255, 1)">from</span> file <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">infer.ml</span><span style="color: rgba(128, 0, 0, 1)">"</span>, line <span style="color: rgba(128, 0, 128, 1)">130</span>, characters <span style="color: rgba(128, 0, 128, 1)">8</span>-<span style="color: rgba(128, 0, 128, 1)">54</span></pre>
</div>
<p>  改成命令:<em><span style="color: rgba(128, 128, 128, 1)">infer&nbsp;<span style="color: rgba(255, 0, 0, 1)">run</span>&nbsp;<span class="nt">-- xcodebuild&nbsp;<span class="nt">-target &lt;target name&gt;&nbsp;<span class="nt">-configuration &lt;build configuration&gt;&nbsp;<span class="nt">-sdk iphonesimulator</span></span></span></span></span></em><span class="nt"><span class="nt"><span class="nt"><span class="nt"> 后解决。</span></span></span></span></p>
<p><span class="nt"><span class="nt"><span class="nt"><span class="nt">  <img src="https://img2018.cnblogs.com/blog/857497/201908/857497-20190801072740474-1831464086.png"></span></span></span></span></p>
<p>  其他用法命令可参考:https://fbinfer.com/docs/analyzing-apps-or-projects.html#xcodebuild</p>
<p>  如果出现:<span class="s1" style="color: rgba(136, 136, 136, 1)">Nothing to compile. Try cleaning the build first.</span></p>
<p>  可使用:<span style="color: rgba(136, 136, 136, 1)">xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator clean,</span>保证增量到非增量转换。</p>
<p>  <img src="https://img2018.cnblogs.com/blog/857497/201908/857497-20190801093634841-466252360.png"></p>
<p>  添加静态分析工具忽略文件:</p>
<p>  &nbsp;在工程目录下新建 .inferconfig 文件,&nbsp;内容如图, 可以过滤掉Pods文件夹下的第三方库, skip-analysis-in-path是一个数组, 想要过滤其他文件, 只需要增加路径即可</p>
<p>  <img src="https://img2018.cnblogs.com/blog/857497/201908/857497-20190801101750721-842344501.png"></p>
<p>&nbsp;</p>
<p>  出现常见错误类型有:</p>
<p>    1、<em><span class="s1" style="color: rgba(128, 128, 128, 1)">NULL_DEREFERENCE:</span></em>空指针的情况。</p>
<p>    <em><span style="color: rgba(128, 128, 128, 1)">1.传参为0的情况下。例如代码中,在调用showAlertViewA()时,将tag传参为0,infer检测此处传0,判断为一个NULL空指针,所以爆出警告。这里可以理解为误报,不会出现问题。</span></em></p>
<p><em><span style="color: rgba(128, 128, 128, 1)">    2.通过malloc,calloc,realloc等函数申请内存,当内存不足时,有可能会在该函数中返回NULL,如果没有做NULL的判断,则警告</span></em></p>
<div>
<div>
<div>
<p><em><span style="color: rgba(128, 128, 128, 1)">    3.在创建NSArray或者NSDictionary时,传入的参数有可能会nil。由于NSArray与NSDictionary不接受空指针,所以在对其addObject或者setObject:forKey:&nbsp;时需要进行判断一下是否为nil</span></em></p>
</div>
    2、<span class="s1"><span style="color: rgba(128, 128, 128, 1)">MEMORY_LEAK</span>:内存泄漏:</span></div>
<div><span class="s1">     项目代码全面启动了ARC进行内存管理,在OC层没有扫描出内存泄露。目前扫描出的内存泄露问题都是使用了malloc或者ralloc等c语言内存申请函数,在函数提前return前没有及时free</span></div>
</div>
<div>
<div>    3、<span class="s1"><span style="color: rgba(128, 128, 128, 1)">RESOURCE_LEAK</span>:资源泄漏</span></div>
<div><span class="s1">    4、<span style="color: rgba(128, 128, 128, 1)">ASSIGN_POINTER_WARNING</span></span></div>
</div>
<div>      由于在mrc时代,没有weak指针,所以一些view的属性声明是_、unsafe__unretain__的形式,在arc中,这个属性被判断为assign,需要将其修改为weak或者strong<br>    5、<span style="color: rgba(128, 128, 128, 1)">DIRECT_ATOMIC_PROPERTY_ACCESS</span></div>
<p>      在代码中使用了使用了一个atomic的成员变量,infer建议我们将atomic修改为nonatomic。由于OC中,属性会被默认设置为atomic属性,我们需要显示将属性声明为nonatomic。</p>
<p>    6、<span style="color: rgba(128, 128, 128, 1)">IVAR_NOT_NULL_CHECKED</span>    </p>
<p>      在代码中调用block,运行代码时,没有做判空处理。即需要改动为,if(block){block()}</p>
<p>    7、<span style="color: rgba(128, 128, 128, 1)">BAD_POINTER_COMPARISON</span></p>
<p>      没有判断一个NSNumber类型的对象是不是空?</p>
<p>    8、<span style="color: rgba(128, 128, 128, 1)">TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION</span></p>
<p>      代码中使用了cookie的value。可以理解为误报</p>
<p>    9、<span style="color: rgba(128, 128, 128, 1)">PARAMETER_NOT_NULL_CHECKED</span></p>
<p>      传参时没有判断是否为null,加一次判断就可以了</p>
<p>    10、<span style="color: rgba(128, 128, 128, 1)">STRONG_DELEGATE_WARNING</span></p>
<p>      将一个delegate属性设置为strong的类型。</p>
<p>    11、<span style="color: rgba(128, 128, 128, 1)">PREMATURE_NIL_TERMINATION_ARGUMENT</span></p>
<p>      没有判断是否为空</p>
<p>    12、<span style="color: rgba(128, 128, 128, 1)">REGISTERED_OBSERVER_BEING_DEALLOCATED</span></p>
<p>      创建一个对象后,监听了某些通知,但是没有在dealloc中释放该通知。项目中出现这种问题的类,基本都是单例,不会被销毁。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<style>p.p1 { margin: 0; font: 12px "Andale Mono"; color: rgba(180, 36, 25, 1); background-color: rgba(0, 0, 0, 0.9) }
span.s1 { font-variant-ligatures: no-common-ligatures }</style>
<style>p.p1 { margin: 0; font: 12px "Andale Mono"; color: rgba(180, 36, 25, 1); background-color: rgba(0, 0, 0, 0.9) }
span.s1 { font-variant-ligatures: no-common-ligatures }</style>
<style>p.p1 { margin: 0; font: 12px "Andale Mono"; color: rgba(180, 36, 25, 1); background-color: rgba(0, 0, 0, 0.9) }
span.s1 { font-variant-ligatures: no-common-ligatures }</style>
<style>p.p1 { margin: 0; font: 12px "Andale Mono"; color: rgba(159, 160, 28, 1); background-color: rgba(0, 0, 0, 0.9) }
span.s1 { font-variant-ligatures: no-common-ligatures }</style>
<style>p.p1 { margin: 0; font: 12px "Andale Mono"; color: rgba(47, 255, 18, 1); background-color: rgba(0, 0, 0, 0.9) }
span.s1 { font-variant-ligatures: no-common-ligatures }</style><br><br>
来源:https://www.cnblogs.com/ZachRobin/p/11280499.html
頁: [1]
查看完整版本: iOS开发之使用 infer静态代码扫描工具