iOS

iOS Crash 分析模型

Posted by summerxx on February 27, 2021

[toc]

前言

分析iOS的Crash要掌握较多的知识,下面我要介绍一个分析模型,可以解决大多数常见Crash, Crash Log分析

1. 查看应用终止的描述

1
2
Application Specific Information:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSInvocation getArgument:atIndex:]: index (0) out of bounds [-1, -1]'

“Application Specific Information”是应用终止的描述,根据这个描述,我们就知道系统干掉App的具体原因,然后可以快速定位问题代码。需要注意的是,不是所有Crash日志都有这部分描述。

2. 查看异常类型和异常码

1
2
3
Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0x110

”Exception Type“描述的是Unix异常信号,我们可以在<sys/signal.h>文件里看到具体的定义。

我们的目的是分析iOS Crash,掌握5个常见的异常类型即可

2.1 SIGABRT信号
1
#define SIGABRT 6       /* abort() */

这个信号触发的最底层代码是abort()。来源可能是NSException,也可能是Mach异常。NSException是未捕获的Objective-C异常,最终会被转化为Unix的SIGABRT信号而崩溃

2.2 SIGSEGV信号
1
#define SIGSEGV 11      /* segmentation violation */

SIGSEGV是段错误,意味访问的指针所对应的地址是无效地址(对应SIGBUS),总体可以归纳为三种非法的内存访问。

第一种,如果地址的数值是0x1xxxxxxxx,这种是正常的内存地址,大概率是访问的内存地址被释放了。第二种,如果地址的数值是0x4或0x8等这样比较小的数值,那大概率访问的内存地址是空指针null,出现的原因通常是汇编指令对空指针进行地址偏移。第三种,如果地址的数值是0x3a321129b9a9008e这种很长很大的数值,这种比较大的概率是野指针,地址还没有从系统映射到当前进程的内存空间。 而野指针一般由于多线程操作对象导致.

2.3 SIGTRAP
1
#define SIGTRAP 5       /* trace trap (not reset when caught) */

TRAP 是陷阱的意思. 第一种是编译器提供的trap方法触发, 如’__builtin_trap()’。第二种是Swift代码运行异常,最终也会转化为SIGTRAP。例如给一个非可选(non-optional)类型被赋值nil 。

1
2
3
4
5
6
Apple SigTrap

Swift code will terminate with this exception type if an unexpected
condition is encountered at runtime such as:
a non-optional type with a nil value
a failed forced type conversion
2.4 SIGBUS
1
#define SIGBUS  10      /* bus error */ 

SIGBUS是总线错误,访问的指针所对应的地址是有效地址(对应SIGSEGV)。具体原因大概率是内存数据未对齐,总线不能正常使用该指针。一般OC代码不会触发,主要是系统库方法或者其他c实现的方法导致。

2.5 SIGILL
1
#define SIGILL  4       /* illegal instruction (not reset when caught) */

SIGILL表示执行了非法的cpu指令。出现的原因可能是试图执行数据段,也可能是代码死循环,导致堆栈溢出。

注:(知识点)iOS Mach异常、Unix信号和NSException异常

3. 查看Crash所在的线程调用栈

Triggered by Thread: 17

1
2
3
4
Thread 17 Crashed:
0   libGPUSupportMercury.dylib      0x000000022d873fe4 _gpus_ReturnNotPermittedKillClient
1   AGXGLDriver                     0x0000000231f21ed8 0x0000000231efd000 + 151256
2   libGPUSupportMercury.dylib      0x000000022d874fac _gpusSubmitDataBuffers

”Triggered by Thread“描述的是Crash发生时所在线程的序列号。比如上面这个例子,Triggered by Thread指向了17号线程,根据序号我们找到”Thread 17 Crashed“的调用栈。调用栈描述的是栈桢,每个栈桢对应一个函数(OC,C,C++),Crash最后一个栈桢是序号0,然后逐渐回溯上层的调用函数。 这就像在凶案现场,法医对死者进行解剖,逐步回溯他身体的变化,最后找到致命伤口。

参考

https://www.jianshu.com/p/04f822f929f0

https://juejin.cn/post/6897962271754944520