IOS静态代码扫描--分析与总结

2020-07-27 15:35:38 浏览数 (1)

IOS静态代码扫描--分析与总结

为了进一步加强代码质量,规范并减少代码缺陷,静态代码扫描是上过环节中必不可少的一部分。大多数都希望通过不同的途径提前发现日常测试中难发现的问题。

然而iOS静态代码扫描工具有不少,它们都有什么不同?我应该选哪一个?因此,本文主要针对主流的几个工具,对同步助手的代码进行扫描,并分析对比它们的扫描结果,再敲定后续的接入计划。

该文章从以下几部分进行阐述,可按需阅读:

一、工具介绍 二、扫描能力对比 三、使用问题总结

01

工具介绍

主流的扫描工具:coverity、infer、clang、oclint

  • 1、coverity

Coverity是检测和解决C、C 、Java和C#源代码中最严重的缺陷的领先的自动化方法。它将基于布尔可满足性验证技术应用于源代码分析引擎,分析引擎利用其专利的软件DNA图谱技术和meta-compilation技术,综合分析源代码、编译构建系统和操作系统等可能使软件产生的缺陷。但这里要注意的是Coverity检测是收费的。

  • 2、clang

Clang作为LLVM编译器框架的前端,最主要的任务是词法分析、语法分析,中间代码生成。源代码通过clang语法分析后,生成了语法分析树(AST)后,可作为静态分析工具对AST进行分析。

Clang命令行调用方法:

(1)下载clang:

代码语言:javascript复制
http://clang-analyzer.llvm.org/

(2)命令行cd到项目代码所在目录:

代码语言:javascript复制
$ cd /path

(3)使用clang扫描,命令开头为clang的scan-build所在目录:

代码语言:javascript复制
$/Users/admin/tools/analyzer/bin/scan-build -vxcodebuild -target QQPimPro -configuration Developer

(4)可以看到生成报告在指定目录下

  • 3、infer

Infer是Facebook开源的用来执行增量分析的一款静态分析工具,由OCaml语言编写的infer目前能检测出空指针访问、资源泄露以及内存泄露,可对C、Java和Objective-C代码进行检测。

Infer命令行调用方法:

安装python 2.7:MAC自带;

安装infer:brew install infer

  • 4、oclint

Oclint是针对C、C 和Objective C代码的静态扫描分析工具,可以和xcode、xcodebuild、xctool等集成,使用命令行方式生成分析报告。这里主要使用oclint对xcodebuild产生的log进行分析,获取相关数据以后生成html文件。

Oclint命令行调用方法:

下载oclint:https://github.com/oclint/oclint/releases(这里注意下,oclint release目前最高0.13 下载releases版本或者使用brew install oclint则不能安装最新版本,在mac 10.14 上无法执行,需要手动进行编译,编译很简单,见下图) http://docs.oclint.org/en/stable/intro/build.html

一、环境配置

需要安装oclintxcpretty

1、安装oclint

方法一:brew安装

命令行执行:

代码语言:javascript复制
$brew tap oclint/formulae
$brew install oclint
方法二:安装包安装

(1)进入到github上,下载最新(当前为oclint-0.13-x86_64-darwin-16.7.0.tar.gz)安装包,解压出来为oclint-0.13,放到如下目录:/Users/layne/OCLint,即路径为/Users/layne/OCLint/oclint-0.13。 (2)将oclint添加到环境变量。vim打开~/.bash_profile(若没有则创建),添加如下代码:

代码语言:javascript复制
OCLINT_HOME=/Users/layne/OCLint/oclint-0.13
 export PATH=$OCLINT_HOME/bin:$PATH

终端执行:

代码语言:javascript复制
 $oclint
代码语言:javascript复制
出现如下内容证明没问题:
代码语言:javascript复制
oclint: Not enough positional command line arguments specified!
 Must specify at least 1 positional argument: See: oclint -help
方法三:源码安装 (若要自定义规则,则必须使用源码方式安装,后边会说到具体方法。)

1、安装CMake和Ninja

代码语言:javascript复制
brew install cmake ninja

CMake和Ninja是代码编译工具,因此必须要先安装。 2、从github上下载oclint源码,解压之后重命名为oclint-0.13,然后放到如下目录(随意):/Users/layne/OCLint,最终为/Users/layne/OCLint/oclint-0.13 3、打开终端进入到/Users/layne/OCLint/oclint-0.13/oclint-scripts

代码语言:javascript复制
cd /Users/layne/OCLint/oclint-0.13/oclint-scripts

然后执行:

代码语言:javascript复制
./make

之后就开始下载和编译,不过时间会比较长(40min左右),且还必须能够爬出去才可以。成功之后会有如下路径:/Users/layne/OCLint/oclint-0.13/build/oclint-release,这个就是oclint的路径。 4、添加oclint到环境变量。执行:

代码语言:javascript复制
vim ~/.bash_profile

将如下内容写入:

代码语言:javascript复制
OCLINT_HOME=/Users/layne/OCLint/oclint-0.13/build/oclint-release
export PATH=$OCLINT_HOME/bin:$PATH

保存退出。重启终端之后在终端执行:oclint --version,出现如下内容:

代码语言:javascript复制
LLVM (http://llvm.org/):
LLVM version 5.0.0svn-r.320669
Optimized build.
Default target: x86_64-apple-darwin17.3.0
Host CPU: broadwell

OCLint (http://oclint.org/):
OCLint version 0.13.
Built Dec 14 2017 (16:03:48).

至此oclint安装成功。

2、安装xcpretty

代码语言:javascript复制
 gem install xcpretty

说明:这里安装的xcpretty是最新版,github上的oclint源码应该是针对最新版的xcpretty进行了兼容。为什么这么说呢?因为我一开始是采用的方法二安装的oclint,运行oclint现成的规则没有问题。之后想要自定义规则,但是方法三又太麻烦了,于是我就偷懒从网上下载了别人事先编译好的oclint-0.12(这里说的"编译好的oclint"保留了当初编译的“现场”,可以进行自定义规则,而方法二中的是“干净“的oclint),然后进行自定义规则,可是跑起来一直报错(形如"/usr/sh fail with exit code 1")。于是乎我不得不用oclint源码重新编译一遍,再运行的时候就没有错误了。

二、xcode配置

以项目LayneStudy为例。

1、创建Aggregate类型target

打开LayneStudy项目,new一个新的target,类型选择Aggregate,命名为OCLint,确定。说明:在xcode9中,Aggregate类型在Cross-platform等目录下(而非iOS、watchOS、macOS等目录下)。

2、编写shell脚本

(1)选择target OCLint,在build phases里添加New Run Script Phase。在框里输入如下脚本代码:

代码语言:javascript复制
 chmod -R 777 $SRCROOT/oclint
 $SRCROOT/oclint/oclint.sh

(2)编写脚本oclint.sh,内容如下:

代码语言:javascript复制
source ~/.bash_profile
 #获取项目路径
 PROJECT_DIR=$(cd `dirname $0`;cd ..;pwd)
 cd ${PROJECT_DIR}

 buildPath="${PROJECT_DIR}/oclint/build"
 compilecommandsJsonFolderPath="${PROJECT_DIR}/oclint"
 compilecommandsJsonFilePath="${PROJECT_DIR}/oclint/compile_commands.json"

 rm -rf "$compilecommandsJsonFolderPath/build"

 xcodebuild SYMROOT=$buildPath | xcpretty -r json-compilation-database -o $compilecommandsJsonFilePath

 cd $compilecommandsJsonFolderPath

 oclint-json-compilation-database -- -report-type xcode 
 -rc CYCLOMATIC_COMPLEXITY=10 
 -rc LONG_CLASS=1000 
 -rc LONG_METHOD=50 
 -rc LONG_LINE=140 
 -rc LONG_VARIABLE_NAME=30 
 -rc SHORT_VARIABLE_NAME=1 
 -rc MAXIMUM_IF_LENGTH=5 
 -rc MINIMUM_CASES_IN_SWITCH=2 
 -rc NCSS_METHOD=30 
 -rc NESTED_BLOCK_DEPTH=5 
 -rc TOO_MANY_METHOD=30 
 -rc TOO_MANY_PARAMETERS=5 
 -max-priority-1 0 
 -max-priority-2 5 
 -max-priority-3 10

将oclint.sh放到项目根目录下的oclint文件夹中(要先创建oclint文件夹)。最终目录结构如下:

代码语言:javascript复制
 ../LayneStudy.xcodeproj
 ../LayneSutdy
 ../oclint
 ../oclint/oclint.sh
3、执行

回到xcode,scheme选择OCLint,command B,编译完成之后xcode则出现各种警告,证明你成功了。

补充:

①若出现python错误,则通过设置环境变量使alias python=python3,即使用最新的python。 ②若出现/Library/Ruby/Gems/2.3.0/gems/xcpretty-0.3.0/lib/xcpretty/parser.rb:434:in `===': invalid byte sequence in US-ASCII (ArgumentError) ”这种错误,则是编码问题:在~/.bash_profile中设置编码:

代码语言:javascript复制
export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

02

扫描能力对比

在未加任何过滤规则的情况下,四个工具对同一份代码进行扫描,并与开发童鞋一起对扫描结果进行了初步筛选和整理:

  • (1)准确率:coverity > infer >clang > oclint;
  • (2)coverity扫描维度更多、发现问题更精准;infer、clang能发现部分coverity未发现的问题,但误报率较高,可作为补充扫描;但这里要说的是coverity是收费的,并且价格还不算便宜
  • (3)infer发现的大部分较为准确(可进行缺陷扫描)
  • (4)oclint扫描出的问题数量最多,但大多是开发不关注的问题,可过滤特定结果类型关注,更适合作为扫描代码复杂度的工具。(但对于代码规范这种定制化较高的需求,使用oclint还是不错的选择)

ps:这里提一下 Xcode提供了一个Analyze功能其实就是集成的clang编译扫描

03

使用问题总结

01

1、缺少证书问题

Build代码的时候可能会遇到缺少了部分证书的问题,因此命令行调用时使用了developer模式,可忽略部分证书问题;

具体命令如下:

代码语言:javascript复制
xcodebuild  build -workspace "${project_name}.xcworkspace" -scheme ${scheme}  -configuration Release  -sdk iphonesimulator COMPILER_INDEX_STORE_ENABLE=NO

02

2、oclint源码编译

由于oclint是基于LLVM编译器框架,基于python进行的编译,在下载内容的过程中需要科学上网,修改编译代码不是一件可取的事情,如果没能力 还是老老实实用别人编译好的吧

03

xcpretty安装

oclint和infer都需要xcpretty,所以要安装xcpretty

0 人点赞