Objective-C - ARC - NSNumber - Грешка в сегментирането

Имам програма goal-C и използвам ARC (автоматично преброяване на препратки), тя хвърля грешка при сегментиране в ред 23 (вижте програмата по-долу).

Въпрос 1) Защо възниква грешката в сегментирането?

По-долу е дадена програмата:

#import<Foundation/Foundation.h>

@interface Car : NSObject
@property (weak) NSNumber* doors;
@end

@implementation Car 
@synthesize doors;
@end

int main()
{
    system("clear");

    @autoreleasepool
    {    
        Car *car1 = [[Car alloc] init];

        printf("1\n");
        NSNumber *d1 = [[NSNumber alloc] initWithInteger: 4]; 

        printf("2\n");
        car1.doors = d1;   //Segmentation fault.. why ?

        printf("3\n");
    }   

    printf("---- end\n");

    return(0);
}

Изход:

1
2
Segmentation fault: 11

person user1046037    schedule 14.11.2011    source източник
comment
Това дава KERN_INVALID_ADDRESS, изглежда като грешка на шината, а не като грешка в сегментирането.   -  person Dani    schedule 14.11.2011
comment
Просто любопитно, има ли причина да използвате printf() вместо NSLog()?   -  person 5StringRyan    schedule 14.11.2011
comment
Просто съм нов в object-C и затова съм склонен да използвам printf   -  person user1046037    schedule 15.11.2011


Отговори (2)


Поздравления: открихте грешка в 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
comment
Благодаря много на всички, беше много полезно и подробно обяснение. - person user1046037; 15.11.2011
comment
Добра работа с отстраняването на грешки... благодаря, че се заехте с това и, да, моля, подайте сигнал за грешка. Подозирам, че е измама, но... за всеки случай... - person bbum; 15.11.2011
comment
Как да отпечатам следата (clang-ARC)? Използвам го от командния ред. Бих искал да знам как мога да отпечатам проследяването на командния ред и когато използвам X-Code какво трябва да направя? - person user1046037; 15.11.2011
comment
Някак си не можах да вляза в връзката към Apple, която бяхте предоставили по-рано, за да докладвам грешката - person user1046037; 15.11.2011
comment
Имате нужда от регистриран акаунт на програмист (безплатен или платен). Уеб сайтът за докладване на грешки обаче не работи през последните няколко дни, така че продължавайте да опитвате! - person ; 16.11.2011
comment
Току-що попаднах и на това и ми се иска просто да бях търсил тук, преди да стигна до същото заключение! +1 за отличен отговор. - person mattjgalloway; 11.01.2012

Публикувайте обратното проследяване. Също така -- каква платформа?

Може да е грешка, свързана с NSNumber и маркирани указатели (ако е насочена към 64-битова OS X).

person bbum    schedule 14.11.2011
comment
Току-що опитах това сам, то се срива вътре в _CFIsDeallocating(). Мислех си, че изглежда и като грешка с маркирани указатели. - person Lily Ballard; 15.11.2011