crash堆栈
1 | Thread 10 name: xxx |
源码
1 | kern_return_t mach_copyMem(const void *const src, void *const dst, const size_t numBytes, int useSafeRange, vm_address_t safeStart, vm_address_t safeEnd) { |
crash现场还原
1 | 0 _demo_ 0x0000000100ae249c _mach_copyMem (in _demo_) (BacktraceLogger.m:516) |
- 计算偏移量
0x0000000100ae249c - 0x100250000 = 0x000000000089249c
- 在xcode调试控制台 获取ipa包的 载入地址
image list demo
1 | (lldb) image list _demo_ |
- 计算实际地址,设置断点
0x00000001000e0000 + 0x000000000089249c = 0x000000010097249c
1 | breakpoint set -a 0x000000010097249c |
分析寄存器与变量之间的对应关系
进入断点后,进行进一步的分析。
1 | _demo_`___lldb_unnamed_symbol39215$$_demo_: |
此处ldr,str指令是memcpy优化生成的指令,用于这种size对齐的内存读写。
对应代码:
1 | memcpy(dst, src, numBytes); |
沿着数据流向分析:1
2x9,来自x0,而x0对应 第1个参数src;
x8,来自x1,对应 第2个参数dst;
此处从src处读取发生crash,说明dst是一个不可读的地址。
接着分析进入这个代码分支的变量值
1 | if (srcAddr > 0x10 |
可以看到safeStart和safeEnd是比较重要的两个值,在执行到0x10097249c的时候这些值对应x4,x5
将x8, x9, x4, x5的数据从crash报告当中读取出来
1 | x4: 0x000000016fab4000(safeStart) x5: 0x000000016fbb0000(safeEnd) |
此处问题就明显了,虽然src依然位于 safeStart 和 safeEnd之间,但是由于 safeEnd - src = 1,也就是说只有1个字节是可读的,因此这里读取的时候就越过了safeEnd,产生了越界。