Objective-C — ARC — NSNumber — Ошибка сегментации

У меня есть программа Objective-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
Я просто новичок в Objective-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 > Application > Command Line Tool. Когда вы запускаете свою программу, 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