Поздравления: открихте грешка в Core Foundation!
Както подозираше Бил, това е свързано с маркирани указатели в Lion. Когато създавате
NSNumber *d1 = [[NSNumber alloc] initWithInteger: 4];
d1
не сочи към действителен екземпляр на NSNumber
. Вместо това d1
е маркиран указател, съдържащ 0x4c3
, където 0x4
е полезният товар в маркирания указател.
Когато се опитате да използвате маркиран указател като стойност на слабо свойство, една от стъпките, изпълнявани от времето за изпълнение на Objective-C, е да изпратите -allowsWeakReference
към екземпляра, за да проверите дали може да се използва като слаба препратка. Тъй като NSNumber
не заменя този метод, изпълнението по подразбиране в NSObject
се изпълнява, което от своя страна изпраща _isDeallocating
, което от своя страна извиква _CFIsDeallocating()
, както е показано в това проследяване на стека:
#0 0x00007fff8ccdbacd in _CFIsDeallocating ()
#1 0x00007fff8ccd3119 in -[__NSCFNumber _isDeallocating] ()
#2 0x00007fff8be34b15 in -[NSObject(NSObject) allowsWeakReference] ()
#3 0x0000000100000ded in main () at test.m:12
Ако прочетете CFRuntime.c, ще видите, че _CFIsDeallocating()
прехвърля съответното показалец към CFRuntimeBase *
, за да прочете _cfinfo
. За нормални обекти на Core Foundation това работи, защото всяка обикновена референция на Core Foundation сочи към екземпляр, който започва с указателя isa
, последван от _cfinfo
. Маркираните указатели обаче не сочат към действителната (разпределена) памет, така че _CFIsDeallocating()
се опитва да дереферира указател, който не е валиден, оттук и грешката в сегментирането.
Трябва да подадете доклад за грешка до Apple. Междувременно използвайте свойство strong
или unsafe_unretained
.
Редактиране: за да получите обратно проследяване, създайте своя изпълним файл с -g
, за да включите информация за отстраняване на грешки, напр.:
$ clang test.m -g -fobjc-arc -framework Foundation -o test
и го стартирайте с GDB:
$ gdb test
…
(gdb) run
Програмата ще се срине:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000000004cb
0x00007fff8ccdbacd in _CFIsDeallocating ()
Използвайте командата bt
в GDB, за да получите обратно проследяване:
(gdb) bt
#0 0x00007fff8ccdbacd in _CFIsDeallocating ()
#1 0x00007fff8ccd3119 in -[__NSCFNumber _isDeallocating] ()
#2 0x00007fff8be34b15 in -[NSObject(NSObject) allowsWeakReference] ()
#3 0x00007fff875173a6 in weak_register_no_lock ()
#4 0x00007fff875179f9 in objc_storeWeak ()
#5 0x0000000100000c0e in -[Car setDoors:] (self=0x100113f60, _cmd=0x100000e7a, doors=0x4c3) at test.m:8
#6 0x0000000100000d45 in main () at test.m:23
и след това командата quit
за излизане от GDB:
(gdb) quit
В Xcode използвайте шаблона Mac OS X > Приложение > Инструмент за команден ред. Когато стартирате вашата програма, Xcode трябва автоматично да покаже GDB подканата в областта за отстраняване на грешки. Ако зоната за отстраняване на грешки не се показва в стандартния редактор, изберете Изглед > Област за отстраняване на грешки > Показване на зона за отстраняване на грешки.
Редактиране: тази грешка беше коригирана в OS X v10.7.3.
person
Community
schedule
15.11.2011