背景
抖音上线 Swift 后,编译时偶现Segmentation fault: 11和Illegal instruction: 4的错误,CI/CD 和本地均有出现,且重新编译后均可恢复正常。
由于属于编译器层抛出的 Crash,加之提示的错误代码不固定且非必现,一时较为棘手。网上类似错误较多,但Segmentation fault属于访问了错误内存的通用报错,参考意义较小。和公司内外的团队交流过,也有遇到类似错误,但原因各不相同,难以借鉴。
虽然 Swift 库二进制化后,相关代码不会参与编译,本地出现的概率大大减少,但在 CI/CD/仓库二进制化任务中依旧使用源码,出现问题需要手动重试,影响效率且繁琐,故深入编译器寻求解决方案。
Crash 堆栈
结论
简而言之,是 Swift 代码中将在 OC 中声明为类属性的NSDictionary变量,当成 Swift 的Dictionary使用。即一个 immutable 变量当作 mutable 变量使用了。编译器在校验SILInstruction时出错,主动调用abort()结束进程或出现EXC_BAD_ACCESS的 Crash。
准备工作
编译 Swift
由于本地重现过错误,故拉取和本地一致的 swift-5.3.2-RELEASE 版本,同时推荐使用 VSCode 进行调试,Ninja 进行构建。
Ninja 是专注于速度的小型构建系统。
注意事项
提前预留 50G 磁盘空间
首次编译时长在一小时左右,CPU 基本打满
下载&编译源码
brew install cmake ninja
mkdir swift-source
cd swift-source
git clone git@github.com:apple/swift.git
cd swift/utils
./update-checkout --tag swift-5.3.2-RELEASE --clone
./build-script
主要目录
提取编译参数
笔者将相关代码抽离抖音工程, 本地复现编译报错问题后,从 Xcode 中提取编译参数:
VSCode 调试
选择合适的 LLDB 插件,以 CodeLLDB 为例配置如下的 launch.json。
其中args内容为获取前一步提取的编译参数,批量将其中每个参数用双引号包裹,再用逗号隔开所得。
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/Ninja-DebugAssert/swift-macosx-x86_64/bin/swift",
"args": ["-frontend","-c","-primary-file"/*and other params*/],
"cwd": "${workspaceFolder}",
}
]
}
SIL
LLVM
在深入 SIL 之前,先简单介绍 LLVM,经典的 LLVM 三段式架构如下图所示,分为前端(Frontend),优化器(Optimizer)和后端

最低0.47元/天 解锁文章
2万+

被折叠的 条评论
为什么被折叠?



