调试过度释放的对象,NSZombie的问题 [英] Debugging over-released objects, problem with NSZombie

查看:361
本文介绍了调试过度释放的对象,NSZombie的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:我发现这个崩溃的原因! bbum指出缓冲区溢出是一个非常常见的原因,所以我查看了我唯一的缓冲区类型malloc:

  closedList =(AINavigationCell **)malloc(baseCells.count * sizeof(AINavigationCell *)); 

我稍后将数据覆盖数据的边界,这应该远远大于 baseCells.count 。谢谢bbum!



问题:
我有一个可重写的 EXC_BAD_ACCESS NSAutoreleasePool -drain中,这似乎表明我已经过度释放了一个对象。所以我启用了 NSZombie ,但是程序不会再崩溃了。也没有任何信息记录到控制台。如果我把NSZombie关掉,那么这个崩溃就回来了。这是什么意思?我认为NSZombies被用来解决这种问题。如果NSZombie不会帮助,还有另一种方式来询问这个过度释放的对象吗?



此外,模拟器中的崩溃不可重现,这就是为什么我不能使用带有NSZombie的仪器。



 #0 _cache_fill()中的0x31ac8bc8 
#1 0x31acaf8e in lookUpMethod ()
#2 0x31ac8780 in _class_lookupMethodAndLoadCache()
#3 0x31ac859a in objc_msgSendSuper_uncached()
#4 0x328014f0 in - [__ NSArrayReverseEnumerator dealloc]()
#5 0x327b1f7a in - [NSObject (NSObject)release]()
#6 0x327b63c8在CFRelease()
#7 0x327b58de在_CFAutoreleasePoolPop()
#8 0x320e132c在NSPopAutoreleasePool()
#9 0x30899048在CAPopAutoreleasePool )
#10 0x30902784在CA :: Display :: DisplayLink :: dispatch()
#11 0x309027ea在CA :: Display :: IOMFBDisplayLink :: callback()
#12 0x30076bfa在IOMobileFramebufferVsyncNotifyFunc ()
#13 IODispatchCalloutFromCFMessage()中的0x333dee6a
#14 __CFMachPortPerform()中的0x327e8be6
#15 0x327e在__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__()
#16 0x327e06c2在__CFRunLoopDoSource1()
#17 0x327d2f7c在__CFRunLoopRun()
#18 0x327d2c86在CFRunLoopRunSpecific()
#19 0x327d2b8e在CFRunLoopRunInMode()$ ($)
#20 0x3094a556 in GSEventRun()
#22 0x32c14328 in - [UIApplication _run]()
#23 0x32c11e92在UIApplicationMain()
#24 0x00002556 in main(argc = 1,argv = 0x2fdff660)at /Users/hyn/Desktop/MyProject-trunk/main.m:14


解决方案

你所描述的问题可能是一些事情之一;您可能会过度释放对象,否则可能会破坏内存。如果你损坏了内存,那么就会损坏一个对象的前几个字节,那么在自动释放池的消耗(或任何其他消息)中,它可以很容易地显示为崩溃。



事件发生在设备上,而不是模拟器,也指向内存损坏。设备[ARM]与模拟器[i386]的架构是完全不同的,有许多问题可能正在发挥。



通常,它并不表现出如此一致。



首先,发布崩溃的回溯。这可能有帮助。



其次,您是否执行任何生成的 malloc 调用?还是用数据填充缓冲区?这种崩溃的最常见原因是运行在缓冲区的末尾。






 #0 0x31ac8bc8 in _cache_fill()
#1 0x31acaf8e in lookUpMethod()
#2 0x31ac8780 in _class_lookupMethodAndLoadCache()
#3 0x31ac859a in objc_msgSendSuper_uncached()
#4 0x328014f0 in - [__ NSArrayReverseEnumerator dealloc]()

(以上是OP修复后添加的问题, - 对于存档)



该崩溃跟踪是内存损坏的经典签名。也就是说, isa 指针 - 指向实例的Class的对象中的第一个指针的字节值被踩踏。这通常发生在您在对象之前分配中的内存缓冲区溢出时。如果它只是一个字节溢出,那么不同平台之间的行为可能会有所不同,因为malloc quanta - 分配的实际大小(在一个平台上要求90个字节,你可能会得到96个。另一个128) - 平台之间有所不同,甚至是版本。



特别是,isa被踩踏,看起来足够像一个指针,运行时解除引用垃圾值,然后尝试将结果位置视为类的方法表。



任何时候,您都可以看到一个崩溃,这是一个深入到 objc_msgSend之一的帧*()函数,很可能是内存损坏,如果是这样,几乎总是缓冲区溢出。



既然是容易做到,仍然是一个好主意,做一个测试通过与僵尸检测抓住有时它只是一个过度释放的情况。


EDIT: I have found the cause of this crash! bbum pointed out that buffer overflows are a very common cause for this, so I looked at the only buffer type malloc I had:

closedList = (AINavigationCell **)malloc(baseCells.count * sizeof(AINavigationCell *));

I was later overwriting data past the array's bounds, which should have been much larger than baseCells.count. Thank you bbum!

Question: I have a reproduceable EXC_BAD_ACCESS during NSAutoreleasePool -drain, which seems to indicate that I am over-releasing an object. So I enable NSZombie, but then the program does not crash any more. Nor do I get any info logged to the console. If I turn NSZombie off, the crash comes back. What is the meaning of this? I thought NSZombies were used to tackle exactly this kind of problem. If NSZombie won't help, is there another way to interrogate this over-released object?

Also the crash is not reproduceable on Simulator, which is why I can't use Instruments with NSZombie.

Folowing is the backtrace at point of crash.

#0  0x31ac8bc8 in _cache_fill ()
#1  0x31acaf8e in lookUpMethod ()
#2  0x31ac8780 in _class_lookupMethodAndLoadCache ()
#3  0x31ac859a in objc_msgSendSuper_uncached ()
#4  0x328014f0 in -[__NSArrayReverseEnumerator dealloc] ()
#5  0x327b1f7a in -[NSObject(NSObject) release] ()
#6  0x327b63c8 in CFRelease ()
#7  0x327b58de in _CFAutoreleasePoolPop ()
#8  0x320e132c in NSPopAutoreleasePool ()
#9  0x30899048 in CAPopAutoreleasePool ()
#10 0x30902784 in CA::Display::DisplayLink::dispatch ()
#11 0x309027ea in CA::Display::IOMFBDisplayLink::callback ()
#12 0x30076bfa in IOMobileFramebufferVsyncNotifyFunc ()
#13 0x333dee6a in IODispatchCalloutFromCFMessage ()
#14 0x327e8be6 in __CFMachPortPerform ()
#15 0x327e06fe in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#16 0x327e06c2 in __CFRunLoopDoSource1 ()
#17 0x327d2f7c in __CFRunLoopRun ()
#18 0x327d2c86 in CFRunLoopRunSpecific ()
#19 0x327d2b8e in CFRunLoopRunInMode ()
#20 0x3094a4aa in GSEventRunModal ()
#21 0x3094a556 in GSEventRun ()
#22 0x32c14328 in -[UIApplication _run] ()
#23 0x32c11e92 in UIApplicationMain ()
#24 0x00002556 in main (argc=1, argv=0x2fdff660) at /Users/hyn/Desktop/MyProject-trunk/main.m:14

解决方案

The problem you describe could be one of a couple of things; you may be over-releasing an object or you might be corrupting memory. If you corrupt memory -- corrupt the first few bytes of an object, specifically -- then it can easily manifest as a crash during an autorelease pool drain (or any other message).

That the crash happens on a device, but not the simulator, points to memory corruption, as well. The architecture of the device [ARM] vs. the simulator [i386] is quite different and there are any of a number of issues that may be at play.

Typically, it doesn't manifest itself quite so consistently.

First, post the backtrace of the crash. It might help.

Secondly, do you do any kind of raw malloc calls? Or filling buffers with data? The most common cause of such crashes is running past the end of a buffer.


#0  0x31ac8bc8 in _cache_fill ()
#1  0x31acaf8e in lookUpMethod ()
#2  0x31ac8780 in _class_lookupMethodAndLoadCache ()
#3  0x31ac859a in objc_msgSendSuper_uncached ()
#4  0x328014f0 in -[__NSArrayReverseEnumerator dealloc] ()

(The above was added after the OP fixed the problem, but -- for the archive)

That crash trace is a classic signature of memory corruption. Namely, the isa pointer -- the first pointer's worth of bytes in an object that points at the Class of the instance -- was stomped. This typically happens when the you overrun a buffer of memory in the allocation before the object. If it is just a couple of byte overrun, then the behavior between different platforms may differ since the malloc quanta -- the real size of the allocations (you ask for 90 bytes on one platform and you might get 96. Another? 128) -- differ between platforms and, even, releases.

In particular, the isa was stomped with a value that looked enough like a pointer that the runtime dereferenced the garbage value and then tried to treat the resulting location as the Class's method table.

Any time you see a crash that is a few frames deep into one of the objc_msgSend*() functions, it is quite likely memory corruption and, if so, it will almost always be a buffer overflow.

Since it is easy to do, it is still a good idea to do a test pass with zombie detection to catch the "sometimes it is really just an over-release cases".

这篇关于调试过度释放的对象,NSZombie的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆