我们收到了一个崩溃日志,该日志指向的一行对于我们所看到的崩溃类型来说没有意义。
这些是崩溃报告中的最上面几行:
Crashed: com.apple.main-thread
0 MyApp 0x676634 specialized static LevelsSessionBeginCoordinator.buildUnitPracticeSession(user:practiceLevelSpecifics:pathLevel:mistakesPracticeTracker:experimentProvider:) + 48 (ClientSizeConstraintsCalculator.swift:48)
1 MyApp 0xd2e58c SkillTreeSessionPreparer.prepareUnitPractice(practiceLevelSpecifics:pathLevel:) + 560 (SkillTreeSessionPreparer.swift:560)
查看 ClientConstraintsCalculator.swift 的第 48 行,其中定义了一个属性:
// ClientSizeConstraintsCalculator.swift
48: private static var maxEmsForMatch: Float = {
49: // pretty straightforward math
...
70: }()
但这很奇怪,因为该行甚至从未从提到的
LevelsSessionBeginCoordinator.buildUnitPracticeSession(...)
函数中调用。
这让团队成员感到困惑,因为这将他们引向错误的方向,不知道会出现什么问题。
查看 Xcode 中包含的崩溃日志,它们具有相同的堆栈跟踪,但前 2 个内存地址已扩展为多个堆栈帧,它甚至给了我们一个非常简单的关于错误的消息:
Thread 0 Crashed:
0 MyApp 0x0000000104982634 Swift runtime failure: Can't get random value with an empty range + 0 (<compiler-generated>:0)
1 MyApp 0x0000000104982634 specialized static FixedWidthInteger.random<A>(in:using:) + 0 (<compiler-generated>:0)
2 MyApp 0x0000000104982634 specialized static FixedWidthInteger.random(in:) + 0 (LevelsSessionBeginCoordinator.swift:705)
3 MyApp 0x0000000104982634 specialized static LevelsSessionBeginCoordinator.buildUnitPracticeSession(user:practiceLevelSpecifics:pathLevel:mistakesPracticeTracker:experimentProvider:) + 768
4 MyApp 0x000000010503a58c specialized static LevelsSessionBeginCoordinator.buildUnitPracticeSession(user:practiceLevelSpecifics:pathLevel:mistakesPracticeTracker:experimentProvider:) + 16 (<compiler-generated>:0)
5 MyApp 0x000000010503a58c static LevelsSessionBeginCoordinator.buildUnitPracticeSession(user:practiceLevelSpecifics:pathLevel:mistakesPracticeTracker:experimentProvider:) + 16 (<compiler-generated>:0)
6 MyApp 0x000000010503a58c SkillTreeSessionPreparer.prepareUnitPractice(practiceLevelSpecifics:pathLevel:) + 80 (SkillTreeSessionPreparer.swift:555)
不仅如此,如果我们转到提到的行,
LevelsSessionBeginCoordinator.swift:705
,我们会看到:
704: let totalRegularSessions = pathLevel.hasLevelReview ? pathLevel.totalSessions - 1 : pathLevel.totalSessions
705: levelSessionIndex = Int.random(in: 0..<totalRegularSessions)
是的,这与苹果工具告诉我们的完全一致。
这里出了点问题。有些东西不起作用。
看看手动操作会向我展示什么,我决定拉起
atos
。找到正在调用的行的内存地址偏移量,我们可以看到它与 Crashlytics 告诉我们的内容相同:
Binary Images:
0x10430c000 - 0x10681ffff MyApp arm64
Crashing Line: 0x0000000104982634
Offset: 0x104982634 - 0x10430c000 = 0x676634
让我们看看
atos
会告诉我们什么:
> atos -o dSYMs/MyApp.dSYM -offset 0x676634
specialized static LevelsSessionBeginCoordinator.buildUnitPracticeSession(user:practiceLevelSpecifics:pathLevel:mistakesPracticeTracker:experimentProvider:) (in MyApp) (LevelsSessionBeginCoordinator.swift:705)
崩溃的是哪条线!
我想提交一份错误报告,但他们说您需要一些“明确定义的错误(带有最小、完整和可验证的示例),但该错误并非特定于您的项目。”这似乎是针对这个实例的,所以我不确定这是否是他们正在寻找的。很抱歉,我为此滥用了堆栈溢出。
我收到了他们的回复。显然这是预料之中的,一切都按计划进行:
根据我们的工程师的说法,当前的行为正在按预期进行。有时,atos 命令确实会将 1 个地址扩展为多行。然而,由于 Crashlytics 从 gSYM 转换为 cSYM,我们只能为每个地址获取一个符号。
当您将 dSYM 上传到 Crashlytics 时,我们会将 dSYM 文件中的 DWARF 内容重新格式化为简单格式,以便在进行符号化时更容易在后端查找。当堆栈跟踪帧地址命中编译器生成的帧时,有时我们能够找到包含类似符号的最近地址以及更准确的文件和行号信息。因此,我们不使用编译器生成,而是交换到应用程序文件中我们可以获得的最接近的行。
根据当前存储代码映射数据的策略,这可能是我们能得到的最接近的策略。 atos 命令可能能够从 DWARF 获取更多信息,或者可能有一些内部苹果工具可以帮助生成诊断消息。
这基本上是我所期待的,但只是想知道其他人是否有任何见解。