介绍 GodEyes-iOS —— iOS 源码 crash 隐患静态扫描工具。

GodEyes-iOS 是一款针对 iOS App 的源码 crash 隐患扫描工具。特点包括:

  1. 专注于 iOS APP 代码的 Crash 隐患静态扫描。
  2. 扫描规则提取自 APP 的典型 crash 案例代码,并且在持续增加中。
  3. 扫描规则可定制,提供多种格式的扫描报告。

一个典型的过程是每次完成你的 iOS 项目的迭代后,就使用 GodEyes 扫描一次你的工程的代码。然后打开扫描结果,定位到上面列举的存在隐患的代码,确认一下是否存在隐患,然后对问题代码进行修改。你也可以很轻松地将它作为持续集成的其中一步,通过解析生成的 json 结果文件,得到当前的代码隐患情况,并作为判断持续集成状态的其中一个项目。

GodEyes-iOS 还有一个兄弟 GodEyes-Android,顾名思义,GodEyes-Android 所针对的是 Android APP 源码的静态扫描。

下文将重点介绍 GodEyes-iOS。出于方便,下文一律将 GodEyes-iOS 简称为 GodEyes。

环境依赖

  • XCode 5 或更高

下载 GodEyes

官网下载:http://godeyes.duapp.com/

本文将主要介绍 v2.0 版本的使用。

配置 GodEyes

打开 conf/config.ini 配置文件,根据你的项目需求,进行如下设置:

  1. projectPath:要扫描的工程路径,即拥有 xxx.xcodeproj 文件或 xxx.xcworkspace 的目录
  2. xctoolCommand:这一步可能需要你费点心思。GodEyes 依赖一个叫做json编译数据库(json Compilation Database)的文件来获取需要扫描的文件列表,而这个文件可以通过调用 GodEyes 内置的第三方工具 xctool 来生成。然而,xctool 并不是很聪明,你需要告诉 xctool 一些关于你项目的必要信息,才能让 xctool 正确生成编译数据库。以下是一个示例:
1
xctoolCommand = xctool/bin/xctool -project ${projectPath}/HelloWorld.xcodeproj -scheme HelloWorld -sdk iphonesimulator -reporter json-compilation-database:${projectPath}/compile_commands.json clean build

其中各参数分别为:

参数 说明
-project-workspace 主工程文件的地址。如果工程文件的后缀名是 xcodeproj ,则通过 -project 指定,后面跟着 xcodeproj 文件的地址;如果工程文件的后缀名是 xcworkspace ,则通过 -workspace 指定,后面跟着 xcworkspace 的地址。
-scheme 要进行扫描的工程方案。你可以在 XCode 中点击 Products->Scheme->Manage Schemes… 来查看当前工程的所有 Scheme 。
-sdk 用于生成编译数据库的编译SDK,不管是 iPhone 还是 iPad 应用,模拟器都为 iphonesimulator,真机都为 iphoneos。
-reporter 这句话告诉 xctool 要生成编译报告,如无特殊情况一般不用修改。
以上参数仅供参考。根据项目的不同,xctoolCommand 需要的指令也不尽相同。如果你在这一步遇到困难,建议你通过 xctool/bin/xctool --help 命令来获取更详细的帮助,或者在网上搜索更多关于如何利用 xctool 生成编译数据库的资料。
  1. threadNum:扫描线程数。GodEyes 支持同时开启多个线程并行工作,以加快扫描速度。
  2. renderType:指定要输出的文件格式,目前支持 html 、json、pmd 三种。
  3. resultNameFormat: 扫描结果文件的命名格式。详见配置文件。
  4. ObjC.XXX:可选的规则。可以通过设定 enable 选项为 true 启用它。部分规则支持配置子扫描项,对于需要排除的扫描项,可以直接删除该项目来规避它。
  5. projectXcodeProjName:若工程配置文件 xxx.xcodeproj 名称与所在目录不一致,可以修改这个选项指定实际的工程配置文件。
  6. excludeList: 若有排除的文件或者目录,请在这里文件中列出,目录或文件之间用逗号隔开。如果不需要排除任何文件,只需将该行注释掉即可。

执行 GodEyes

完成配置后,cd 进入 godeyes 目录,然后直接 sh run.sh 执行脚本即可。

GodEyes-iOS 执行过程演示
GodEyes-iOS 执行过程演示

如果你看到红色的文字,就说明检测到了可能存在 crash 隐患的代码。扫描完成后,可以通过阅读生成的结果文件获得更详细的扫描结果。一份 HTML 格式的扫描结果如下所示:

如果之前已经使用 GodEyes 扫描过你的工程,那么再次使用 GodEyes 时会提示你是否要覆盖编译数据库,如下图所示:

如果你的工程文件列表已经发生改变(比如增删了代码文件,或改动了文件位置),则需要输入 y 重新生成编译数据库。如果想每次输入都自动重新创建编译数据库,则可以在执行脚本时跟上 -f 参数。否则可以输入 n ,直接利用之前创建好的编译数据库,以节省时间。

执行 run.sh 时,还支持带有如下一些命令行参数:

参数 说明
-l 列举所有已启用的规则。
-d 诊断模式,在执行扫描时会打印出更多的错误信息以便于诊断。通常情况下不需要开启这个选项。
-f 每次运行时都默认重新生成编译数据库,而不再弹出询问信息,适合需要跑自动化的用户。
-h 打印帮助信息。

常见问题

Q 运行过程中出现 "[GodEyes] Error occurs while generating compilation database." 错误。
A 出现这个错误意味着你的 xctoolCommand 没有配对,导致编译数据库没有正确生成。请详细阅读 xctool 的说明。只有按照 xctool 的说明写好 xctoolCommand 生成编译数据库,才能在下一步调用 GodEyes 进行静态扫描。你可以在 GodEyes 的根目录执行:
1
xctool/bin/xctool --help

来打印 xctool 的帮助,也可以访问 xctool 的 Github 主页获得更多的帮助。

Q 运行过程中出现 "LLVM ERROR: Could not auto-detect compilation database for file XXX/XXX/XXX"、"No compilation database found in XXX/XXX/XXX or any parent directory。" 等类似错误。
A 如果这些引发错误的源文件并非来自你的主工程,而是来自第三方库,你需要将这些第三方库的路径添加到排除列表中。如果你希望 GodEyes 扫描这些第三方库,可以直接拷贝一份 GodEyes ,然后为这些第三方库编写配置文件,再完成扫描。
Q 运行过程中出现 "[GodEyes] Another GodEyes instance is running!" 错误。
A GodEyes 运行时会在当前目录下创建一个 godeyes.tmp 临时文件,以记录程序的配置信息。为了避免多个 GodEyes 进程同时对同个临时文件进行读写导致意外错误,在任意时刻只允许运行一个 GodEyes 进程。所以,如果你遇到这个错误,请等待上一个 GodEyes 程序运行完成。如果你确定当前没有运行其他 GodEyes 程序,可以手动将 godeyes.tmp 文件删除。

如果确实需要同时启用多个 GodEyes 扫描多个工程,可以再拷贝一份 GodEyes 目录,删掉新目录下的 godeyes.tmp 文件,然后在不同的目录下执行各自的 GodEyes 程序,由于读取的是不同位置的 godeyes.tmp 临时文件,就不会出现这个问题。

Q 扫描得到的 json 结果文件怎么阅读?
A 首先建议使用 JSON 格式化工具阅读该文件里的内容:[http://www.w3cschool.cc/tool/json/index.html](http://www.w3cschool.cc/tool/json/index.html) 。

一个经过格式化的 json 结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"status": "ok"
"results": [
{
"rule_name": "ObjC.ReturnTypeInconsistent"

"type": "ReturnTypeInconsistentRule",

"num": "1",

"rule_result": [
{
"lines": "75,",
"file": "/Users/wzpan/Documents/workspace/HelloWorld/HelloWorld/MyCircle.m"
}
],

}
],
}

json 是逐条规则列出违反清单的。

  • rule_name 是规则名,你可以在 config.ini 或 tpl/RuleName 里找到对应的中文名。
  • num 是违反规则的次数。
  • rule_result 是违反规则的位置。

从上面的结果可以看出,该项目违反了 1 次“函数返回值必须与实际返回类型一致隐患”规则,违反位置在 /Users/wzpan/Documents/workspace/HelloWorld/HelloWorld/MyCircle.m 文件中的第 75 行。

Q GodEyes-iOS 有哪些局限性?
A 下面这些情况是 GodEyes-iOS 目前无法正常处理的:
  • 不能解析宏。这意味着如果你使用了宏来检测版本,则可能会导致 API 兼容性规则误报;
  • 不能理解用户自定义的类型。这意味着 GodEyes 无法对从 NS 数据结构类继承而来的自定义类型应用相关的 NS 数据结构的规则;
  • 不支持动态分析。这意味着如果你的代码中存在一些运行时才能获取的状态,则可能导致与 GodEyes 规则冲突时产生误报。
Q GodEyes-iOS 的扫描结果有误报呀。
A 如果出现误报,而且不属于上一个问题列出的几种情况,可以 [联系开发者](mailto:2983512772@qq.com) ,告诉我们误报的规则名以及涉及的代码,以便进行修复。

Comments