点赞评论,感觉有用的朋友可以关注笔者公众号 iOS 成长指北,持续更新
原书为 iOS Crash Dump Analysis Book,已得作者授权,欢迎 star
在本章中,我们将学习错误的内存崩溃。
在崩溃报告中,我们可以通过异常类型 EXC_BAD_ACCESS (SIGSEGV)
或 EXC_BAD_ACCESS (SIGBUS)
来进行区分。
我们来看看通过搜索互联网获得的一系列崩溃。
一般原则
在操作系统中,管理内存的方法是首先将连续的内存排序为内存页,然后将页面排序为段。 这允许将元数据属性分配给应用于该段内的所有页面的段。这允许我们的程序代码(程序 _TEXT _ )被设置为只读但可执行。提高了性能和安全性。
SIGBUS(总线错误)表示内存地址已正确映射到进程的地址区间,但不允许进程访问内存。
SIGSEGV(段冲突)表示存储器地址甚至没有映射到进程地址区间。
段冲突 (SEGV)崩溃
fud 崩溃
fud
程序是私有框架 MobileAccessoryUpdater
中的一个未记录的进程。
在这里,我们显示了macOS上进程 fud
的崩溃报告,为了便于演示,该报告已被截断:
Process: fud [84641]
Path: /System/Library/PrivateFrameworks/
MobileAccessoryUpdater.framework/Support/fud
Identifier: fud
Version: 106.50.4
Code Type: X86-64 (Native)
Parent Process: launchd [1]
Responsible: fud [84641]
User ID: 0
Date/Time: 2018-06-12 08:34:15.054 +0100
OS Version: Mac OS X 10.13.4 (17E199)
Report Version: 12
Anonymous UUID: 6C1D2091-02B7-47C4-5BF9-E99AD5C45875
Sleep/Wake UUID: 369D13CB-F0D3-414B-A177-38B1E560EEC7
Time Awake Since Boot: 240000 seconds
Time Since Wake: 47 seconds
System Integrity Protection: enabled
Crashed Thread: 1
Dispatch queue: com.apple.fud.processing.queue
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [0]
Thread 1 Crashed:: Dispatch queue:
com.apple.fud.processing.queue
0 libdispatch.dylib 0x00007fff67fc6cbd
_dispatch_continuation_push + 4
1 fud 0x0000000101d3ce57
__38-[FudController handleXPCStreamEvent:]_block_invoke + 593
2 libdispatch.dylib 0x00007fff67fbb64a
_dispatch_call_block_and_release + 12
3 libdispatch.dylib 0x00007fff67fb3e08
_dispatch_client_callout + 8
4 libdispatch.dylib 0x00007fff67fc8377
_dispatch_queue_serial_drain + 907
5 libdispatch.dylib 0x00007fff67fbb1b6
_dispatch_queue_invoke + 373
6 libdispatch.dylib 0x00007fff67fc8f5d
_dispatch_root_queue_drain_deferred_wlh + 332
7 libdispatch.dylib 0x00007fff67fccd71
_dispatch_workloop_worker_thread + 880
8 libsystem_pthread.dylib 0x00007fff68304fd2
_pthread_wqthread + 980
9 libsystem_pthread.dylib 0x00007fff68304be9
start_wqthread + 13
Thread 1 crashed with X86 Thread State (64-bit):
rax: 0xe00007f80bd22039 rbx: 0x00007f80bd2202e0
rcx: 0x7fffffffffffffff
rdx: 0x011d800101d66da1
rdi: 0x00007f80bd21a250 rsi: 0x0000000102c01000
rbp: 0x0000700007e096c0
rsp: 0x0000700007e09670
r8: 0x0000000102c00010 r9: 0x0000000000000001
r10: 0x0000000102c01000
r11: 0x00000f80b5300430
r12: 0x00007f80ba70c670 r13: 0x00007fff673c8e80
r14: 0x00007f80bd201e00
r15: 0x00007f80ba70cf30
rip: 0x00007fff67fc6cbd rfl: 0x0000000000010202
cr2: 0x00007fff9b2f11b8
Logical CPU: 3
Error Code: 0x00000004
Trap Number: 14
我们显然有一个不好的内存问题,因为我们有一个EXC_BAD_ACCESS (SIGSEGV)
(SIGSEGV)异常。 我们看到的错误代码是 14,在 https://github.com/apple/darwin-xnu 中这属于缺页中断。
由于 libdispatch
是 Apple 开源的,我们甚至可以查找触发崩溃的函数。
我们看到:
#define dx_push(x, y, z) dx_vtable(x)->do_push(x, y, z)
DISPATCH_NOINLINE
static void
_dispatch_continuation_push(dispatch_queue_t dq,
dispatch_continuation_t dc)
{
dx_push(dq, dc, _dispatch_continuation_override_qos(dq,
dc));
}
我们正在从一个有错误内存位置的数据结构中解除内存引用。
我们可以反汇编问题调用站点的macOS二进制文件/usr/lib/system/libdispatch.dylib
。
在这里,我们使用 Hopper 进行脱壳:
__dispatch_continuation_push:
0000000000014c69 push rbx
; CODE XREF=__dispatch_async_f2+112,
j___dispatch_continuation_push
0000000000014c6a mov rax, qword [rdi]
0000000000014c6d mov r8, qword [rax+0x40]
0000000000014c71 mov rax, qword [rsi+8]
0000000000014c75 mov edx, eax
0000000000014c77 shr edx, 0x8
0000000000014c7a and edx, 0x3fff
0000000000014c80 mov ebx, dword [rdi+0x58]
0000000000014c83 movzx ecx, bh
0000000000014c86 je loc_14ca3
rdi
寄存器值似乎有问题,地址为 0x00007f80bd21a250
我们需要退一步,了解为什么我们有内存访问问题。
查看堆栈回溯,我们可以看到该程序使用跨进程通信(XPC)来完成其工作。 它有 handleXPCStreamEvent
函数。
这是一个常见的编程问题,当我们接收到一个数据有效负载时,就会出现解压缩有效负载和解释数据的问题。我们推测反序列化代码中有一个bug。这将给我们一个潜在的坏数据结构,我们取消引用会导致崩溃。
如果我们是fud
程序的作者,我们可以对其进行更新以检查它获得的XPC数据,并确保遵循最佳实践进行数据的序列化/反序列化,例如使用接口定义层生成器。
LeakAgent 崩溃
苹果提供了 LeakAgent
程序作为其内存诊断工具的一部分。 它在 Xcode Instruments 中使用。
以下是崩溃报告, LeakAgent
发生了崩溃,为了便于演示而被截断:
Incident Identifier: 11ED1987-1BC9-4F44-900C-AD07EE6F7E26
CrashReporter Key: b544a32d592996e0efdd7f5eaafd1f4164a2e13c
Hardware Model: iPad6,3
Process: LeakAgent [3434]
Path: /Developer/Library/PrivateFrameworks/
DVTInstrumentsFoundation.framework/LeakAgent
Identifier: LeakAgent
Version: ???
Code Type: ARM-64 (Native)
Role: Unspecified
Parent Process: DTServiceHub [1592]
Coalition: com.apple.instruments.deviceservice
[463]
Date/Time: 2018-07-19 14:16:57.6977 +0100
Launch Time: 2018-07-19 14:16:56.7734 +0100
OS Version: iPhone OS 11.3 (15E216)
Baseband Version: n/a
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at
0x0000000000000000
VM Region Info: 0 is not in any region.
Bytes before following region: 4371873792
REGION TYPE START - END
[ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 0000000104958000-0000000104964000
[ 48K] r-x/r-x SM=COW ...ork/LeakAgent
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [0]
Triggered by Thread: 4
Thread 4 name: Dispatch queue:
DTXChannel serializer queue [x1.c0]
Thread 4 Crashed:
0 libswiftDemangle.dylib
0x0000000104f871dc 0x104f70000 + 94684
1 libswiftDemangle.dylib
0x0000000104f8717c 0x104f70000 + 94588
2 libswiftDemangle.dylib
0x0000000104f86200 0x104f70000 + 90624
3 libswiftDemangle.dylib
0x0000000104f84948 0x104f70000 + 84296
4 libswiftDemangle.dylib
0x0000000104f833a4 0x104f70000 + 78756
5 libswiftDemangle.dylib
0x0000000104f73290 0x104f70000 + 12944
6 CoreSymbolication
0x000000019241d638 demangle + 112
7 CoreSymbolication
0x00000001923d16cc
TRawSymbol<Pointer64>::name+ 54988 () + 72
8 CoreSymbolication
0x0000000192404ff4
TRawSymbolOwnerData<Pointer64>::
symbols_for_name(CSCppSymbolOwner*, char const*,
void + 266228 (_CSTypeRef) block_pointer) + 156
9 CoreSymbolication
0x00000001923d9734
CSSymbolOwnerGetSymbolWithName + 116
10 Symbolication
0x000000019bb2e7f4
-[VMUObjectIdentifier _targetProcessSwiftReflectionVersion]
+ 120
11 Symbolication
0x000000019bb2f9d8
-[VMUObjectIdentifier loadSwiftReflectionLibrary] + 36
12 Symbolication
0x000000019bb29ff0
-[VMUObjectIdentifier initWithTask:symbolicator:scanner:]
+ 436
13 Symbolication
0x000000019baede10
-[VMUTaskMemoryScanner _initWithTask:options:] + 2292
14 Symbolication
0x000000019baee304
-[VMUTaskMemoryScanner initWithTask:options:] + 72
15 LeakAgent
0x000000010495b270 0x104958000 + 12912
16 CoreFoundation
0x0000000183f82580 __invoking___ + 144
17 CoreFoundation 0x0000000183e61748
-[NSInvocation invoke] + 284
18 DTXConnectionServices
0x000000010499f230 0x104980000 + 127536
19 DTXConnectionServices
0x00000001049947a4 0x104980000 + 83876
20 libdispatch.dylib 0x000000018386cb24
_dispatch_call_block_and_release + 24
21 libdispatch.dylib 0x000000018386cae4
_dispatch_client_callout + 16
22 libdispatch.dylib 0x0000000183876a38
_dispatch_queue_serial_drain$VARIANT$mp + 608
23 libdispatch.dylib 0x0000000183877380
_dispatch_queue_invoke$VARIANT$mp + 336
24 libdispatch.dylib 0x0000000183877d4c
_dispatch_root_queue_drain_deferred_wlh$VARIANT$mp + 340
25 libdispatch.dylib 0x000000018388011c
_dispatch_workloop_worker_thread$VARIANT$mp + 668
26 libsystem_pthread.dylib 0x0000000183b9fe70
_pthread_wqthread + 860
27 libsystem_pthread.dylib
0x0000000183b9fb08 start_wqthread + 4
Thread 4 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000000 x1: 0x0000000000000000
x2: 0xfffffffffffffff6
x3: 0x0000000000000041
x4: 0x0000000000000000 x5: 0x0000000104f97950
x6: 0x0000000000000006
x7: 0x00000000ffffffff
x8: 0x00000001050589d0 x9: 0x0000000104f840d8
x10: 0xffffffffffffd544
x11: 0x0000000000000a74
x12: 0x0000000000000002 x13: 0x00000000000002aa
x14: 0x00000000000002aa
x15: 0x00000000000003ff
x16: 0x0000000183b96360 x17: 0x0000000000200000
x18: 0x0000000000000000
x19: 0x000000016b6d1ba0
x20: 0x00000001050589a0 x21: 0x0000000000000000
x22: 0x0000000000000000
x23: 0x0000000000000001
x24: 0x00000000ffffffff x25: 0x0000000000000006
x26: 0x0000000104f97950
x27: 0x0000000000000000
x28: 0x0000000000000009 fp: 0x000000016b6d19c0
lr: 0x0000000104f8717c
sp: 0x000000016b6d1930 pc: 0x0000000104f871dc
cpsr: 0x60000000
我们可以看到出错的内核地址是0x0000000000000000
,所以它是一个空指针解引用。我们崩溃的调用站点是一个分解符号的 Swift 库。Xcode 工具试图从它在 iPad 上看到的活动中提供人类可读的对象类型定义。
如果我们是用户并视图分析我们的应用程序,然后在LeakAgent
中遇到此错误,那么我们需要尝试找出避免该问题的方法。
由于问题是由于符号化造成的,所以明智的做法是清除构建目录,然后进行一次干净的构建。有时,Xcode更新会将我们切换到不兼容的新目标文件格式。 值得与另一个项目(可能是微不足道的测试程序)一起检查性能。 还有其他内存分析工具,例如我们正在运行的方案的诊断选项,因此可以用不同的方式进行内存分析。 有关更多信息,请参见下一章内存诊断 。
指针验证机制崩溃
之前,在 指针验证机制 一章中,我们看到了用户启用指针验证机制会导致崩溃。接下来我们看一些使用指针验证机制的系统库发生的崩溃。
Incident Identifier: 692E5696-6994-4FB3-B42D-C9317D956EE7
CrashReporter Key: 1f2cdb7448d354584634e8576c1e5257634fc0cd
Hardware Model: iPhone12,1
Process: get [1737]
Path:
/private/var/containers/Bundle/Application/2BF678BB-7CC6-4CAC-BF
49-0298B611F1BA/get.app/get
Identifier:
com.soul.merge.cat.cute.simulator.adventure.get
Version: 44 (1.4.4)
AppStoreTools: 11C29
AppVariant: 1:iPhone12,1:13
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition:
com.soul.merge.cat.cute.simulator.adventure.get [757]
Date/Time: 2019-12-26 09:54:15.6806 +0300
Launch Time: 2019-12-26 09:43:08.8423 +0300
OS Version: iPhone OS 13.3 (17C54)
Release Type: User
Baseband Version: 1.03.12
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x41fc821e000001b0 ->
0xffffff9e000001b0 (possible pointer authentication failure)
VM Region Info: 0xffffff9e000001b0 is not in any region. Bytes
after previous region: 18446743641528467889
REGION TYPE START - END [
VSIZE] PRT/MAX SHRMOD REGION DETAIL
MALLOC_NANO 0000000280000000-00000002a0000000
[512.0M] rw-/rwx SM=PRV
--->
UNUSED SPACE AT END
Triggered by Thread: 27
Thread 27 name:
Thread 27 Crashed:
0 libEmbeddedSystemAUs.dylib 0x00000001d0246644
InterruptionListener(void*, unsigned int, unsigned int, void
const*) + 352 (AURemoteIO.cpp:257)
1 libEmbeddedSystemAUs.dylib 0x00000001d0246578
InterruptionListener(void*, unsigned int, unsigned int, void
const*) + 148 (AURemoteIO.cpp:256)
2 AudioToolbox 0x00000001bd34e710
AudioSessionPropertyListeners::CallPropertyListeners(unsigned
int, unsigned int, void const*) + 596
(AudioSessionPropertyListeners.cpp:146)
3 AudioToolbox 0x00000001bd3ab564
HandleAudioSessionCFTypePropertyChangedMessage(unsigned int,
unsigned int, void*, unsigned int) + 1104 (AudioSession.cpp:932)
4 AudioToolbox 0x00000001bd3aac1c
ProcessDeferredMessage(unsigned int, __CFData const*, unsigned
int, unsigned int) + 2540 (AudioSession.cpp:1050)
5 AudioToolbox 0x00000001bd4187e0
_XAudioSessionPingMessage + 688 (AudioSession.cpp:1161)
6 libAudioToolboxUtility.dylib 0x00000001bd4a76b4
mshMIGPerform + 268 (MachServerHelper.c:450)
7 CoreFoundation 0x00000001b1f207c4
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
(CFRunLoop.c:1937)
8 CoreFoundation 0x00000001b1f1fe90
__CFRunLoopDoSource1 + 448 (CFRunLoop.c:2075)
9 CoreFoundation 0x00000001b1f1aac8
__CFRunLoopRun + 2144 (CFRunLoop.c:3098)
10 CoreFoundation 0x00000001b1f19f40
CFRunLoopRunSpecific + 480 (CFRunLoop.c:3192)
11 AVFAudio 0x00000001beeb1f70
GenericRunLoopThread::Entry(void*) + 160
(GenericRunLoopThread.h:91)
12 AVFAudio 0x00000001bef031fc
CAPThread::Entry(CAPThread*) + 208 (CAPThread.cpp:286)
13 libsystem_pthread.dylib 0x00000001b1cad840
_pthread_start + 168 (pthread.c:896)
14 libsystem_pthread.dylib 0x00000001b1cb59f4
thread_start + 8
Thread 27 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000000 x1: 0x0000000000000000 x2:
0x0000000000000100 x3: 0x0000000000000000
x4: 0x00000000000020a0 x5: 0x0000000000000020 x6:
0x0000000000000000 x7: 0x00000000000003da
x8: 0x41fc821e00000000 x9: 0x0000000000000020 x10:
0x0000000000000000 x11: 0x0000000000000202
x12: 0x0000000000000002 x13: 0x0000000000000000 x14:
0x0000000000000002 x15: 0x0000000000000001
x16: 0x00000001b1c6b43c x17: 0x00000001f0430630 x18:
0x0000000000000000 x19: 0x0000000103823040
x20: 0x00000001710287fc x21: 0x00000000696e7472 x22:
0x0000000108aa3b28 x23: 0x000000010fd10588
x24: 0x000000010fd105a0 x25: 0x0000000064696564 x26:
0x00000001fb421000 x27: 0x00000000006c9000
x28: 0x0000000000000049 fp: 0x0000000171028660 lr:
0xe970e981d0246578
sp: 0x0000000171028600 pc: 0x00000001d0246644 cpsr:
0x80000000
esr: 0x56000080 Address size fault
Binary Images:
0x10005c000 - 0x102687fff get arm64
<bde08a08d8cf3e6b8cee8ab2cf246ccb>
/var/containers/Bundle/Application/2BF678BB-7CC6-4CAC-BF49-0298B
611F1BA/get.app/get
.
.
0x1d01b7000 - 0x1d02c3fff libEmbeddedSystemAUs.dylib arm64e
<48e72efe02243faabf3e1760bb4c2731>
/System/Library/Frameworks/AudioToolbox.framework/libEmbeddedSys
temAUs.dylib
这里,我们看到故障地址 0x41fc821e000001b0
最高 24 位为41fc82
。 这就是 指针校验验证码(PAC)。\index{PAC}
我们看到故障函数 InterruptionListener
使用两个指针作为参数,并且我们已经将寄存器 x8
的地址设置为0x41fc821e00000000
。 因此,大概我们的失败代码正在使用该地址,加上一些小的偏移量 0x1b0
。 这可能是由于使用了手动指针算法,导致使用了未经身份验证的指针。
感谢你阅读本文! 🚀