Swift编译器Crash—Segmentation fault解决方案

背景

抖音上线 Swift 后,编译时偶现Segmentation fault: 11Illegal 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)和后端(Backend)。当需要支持新语言时只需实现前端部分,需要支持新的架构只需实现后端部分,而前后端的连接枢纽就是 IR(Intermediate Representation),IR 独立于编程语言和机器架构,故 IR 阶段的优化可以做到抽象而通用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值