Отладка перезагруженных объектов, проблема с NSZombie - PullRequest
4 голосов
/ 31 января 2011

РЕДАКТИРОВАТЬ : Я нашел причину этого сбоя!bbum отметил, что переполнение буфера является очень распространенной причиной этого, поэтому я посмотрел на единственный тип буфера malloc, который у меня был:

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

Позже я перезаписывал данные за пределы массива, что должно было быть оченьбольше чем baseCells.count.Спасибо, bbum!

Вопрос: У меня есть воспроизводимый EXC_BAD_ACCESS во время NSAutoreleasePool -дрейна, который, кажется, указывает на то, что я переусердствовал с объектом.Поэтому я включаю NSZombie, но тогда программа больше не падает.Также я не получаю информацию, записываемую на консоль.Если я выключу NSZombie, авария вернется.Что это означает?Я думал, что NSZombies были использованы для решения именно такой проблемы.Если NSZombie не поможет, есть ли другой способ опросить этот перевыпущенный объект?

Также сбой не воспроизводится на симуляторе, поэтому я не могу использовать инструменты с NSZombie.

Фолловинг - это обратный след в точке сбоя.

#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

1 Ответ

16 голосов
/ 31 января 2011

Проблема, которую вы описываете, может быть одной из нескольких вещей;возможно, вы чрезмерно выпускаете объект или вы повреждаете память.Если вы повредите память - в частности, первые несколько байтов объекта - тогда это может легко проявиться как сбой во время очистки пула автоматического выпуска (или любого другого сообщения).

То, что сбой происходит наУстройство, но не симулятор, также указывает на повреждение памяти.Архитектура устройства [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 - значение байта первого указателя в объекте, который указывает на класс экземпляра - был растоптан.Обычно это происходит, когда вы переполняете буфер памяти при выделении перед объектом.Если это просто переполнение пары байтов, то поведение между разными платформами может отличаться, так как кванты malloc - реальный размер выделений (вы запрашиваете 90 байтов на одной платформе, и вы можете получить 96. Другая? 128) -- различаются между платформами и даже выпусками.

В частности, isa был растоптан со значением, которое выглядело достаточно как указатель, чтобы среда выполнения разыменовывала значение мусора, а затем пыталась обработать полученное местоположение как класс.таблица методов.

Каждый раз, когда вы видите сбой в нескольких кадрах глубоко в одной из objc_msgSend*() функций, вполне вероятно повреждение памяти и, если так, почти всегда будет переполнение буфера.

Так как это легко сделать, все же хорошей идеей будет сделать тестовый проход с обнаружением зомби, чтобы уловить «иногда это просто перевыпуск».

...