原文链接
问题产生的原因
程序崩溃在objc_msgSend(),最有可能的原因是向一个已经释放的对象发送消息。
其他的原因如下:
1.也许你的指针是完全正确的,但是别的缺胳膊少腿的对象的内容可能是溢出在附近的一个分配的缓冲区。
2. 或者使用重复的指针指向现在你的对象所占用的内存。
3.极个别objc_msgSend()崩溃是因为内存被破坏,但通常的问题是在接收对象本身。
解决问题的方法
1. 找到接收消息的对象和转换器(selector )注册的所有对象。
objc_msgSend()存储了receiver和the selector在cpu的寄存器中。不同的架构的cpu寄存器的名称不同
objc_msgSend objc_msgSend_fpret | objc_msgSend_stret | |||
receiver | SEL | receiver | SEL | |
i386 | eax* | ecx | eax* | ecx |
x86_64 | rdi | rsi | rsi | rdx |
ppc | r3 | r4 | r4 | r5 |
ppc64 | r3 | r4 | r4 | r5 |
arm | r0 | r1 | r1 | r2 |
arm64 | x0 | x1 | — | — |
在调试器控制台中,当程序停止时,打印无效地址,您可以打印上面的表中使用的寄存器名称的接收者的地址。
以下是在Xcode 5.1连接ipad的结果
(lldb) re r -f b r0
r0 = 0b00100011001110111100110000010000
转换成16进制
(lldb) re r -f b r0 --format x
r0 = 0x233bcc10
对应的gdb的指令为
(gdb) p/x $eax $1 = 0x1
通常情况下,会有以下两种情况:
1. 接收地址本身是假的,而无效的地址是相同的值(或16或32字节的距离)。
2. 接收器的地址是合理的,无效的地址使用的是接收对象的isa指针。通常是你试图使用一个已经释放的对象或其他地方破坏您的有效对象。
常见的错误
没对齐 - 16位对齐
malloc返回16位对齐的块,如果你的接受者对象不是16位对齐的会产生一个无效的指针。
分配和释放列表: top和底部的两位都设置(malloc free list)
当一个块被释放后,内存分配器可以写空闲链表指针进去。如果在此之后使用已释放的对象,你会看到一个isa指针与top和底部的两位全部设置。
倒置所有位 - gc释放列表
像malloc的空闲列表上方的情况下,而是由垃圾回收器造成的,而不是。在这种情况下地址看起来不错,但是〜地址是比较合理的。
0xa1b1c1d3 - CF容器
CoreFoundation容器使用此值删除或空项。也许一个释放的对象已被重新分配为一个容器,或者是有人使用已重新分配为你的对象已释放的容器,或者您从已同时被其他线程改变了容器读取指针而你不知道有正确的锁定到位。
ASCII文本
也许一个释放的对象已被重新分配为一个字符串,或者是有人使用已重新分配为你的对象已释放的字符串,或者一些字符串操作有一个缓冲区溢出。使用asciify在两个endians这些快速打印。这一个看起来网址相关的,例如:
./asciify 0x2e777777
###.www###
###www.###
查找selector
1. 编译器的优化意味着调用堆栈指向的回溯第二帧可能不是真正crash调用。这有可能是调用成功,然后该方法做了一个尾调用它是一个崩溃。由于尾调用优化,中间帧将丢失从回溯。我们可以使用选择寄存器,以确定什么是真正的崩溃调用了。
选择器是一个指针,指向一个唯一的C字符串。这可能会在未来的OS版本改变,但现在它的方便调试。如果你已经crash在一个调试器,打开调试器控制台,并运行这一点,从以上表格用正确的SEL寄存器:(selector)
将寄存器中得值作为一个字符串打印
(gdb) x/s $ecx 0xa1029: "release"
2. 如果只有一个日志文件,查找是很困难
1)在日志中找到seletor的地址
ecx: 0x000a1029
2)根据地址确定在那个库中
0x8b000 - 0x106ff7 libobjc.A.dylib ??? (???) <9b5973b7fa88f9aab7885530c7b278dd> /usr/lib/libobjc.A.dylib
3)使用dwarfdump检查dSYM和app是否匹配(崩溃日志也有这个UUID)
% dwarfdump -u /usr/lib/libobjc.A.dylib
UUID: 26650299-C6EA-B1C8-52D6-072AC874D400 (ppc) /usr/lib/libobjc.A.dylib
UUID: 9B5973B7-FA88-F9AA-B788-5530C7B278DD (i386) /usr/lib/libobjc.A.dylib
UUID: D2A4E8E1-3C1C-E0D9-2249-125B6DD621F8 (x86_64) /usr/lib/libobjc.A.dylib
4)计算地址偏移
0xa1029 - 0x8b000 = 0x16029
5)根据偏移打出对应的字符串
% otool -v -arch i386 -s __TEXT __cstring /usr/lib/libobjc.A.dylib | grep 16029
00016029 release