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

У меня есть программа objective-C, и я использую ARC (Automatic Reference Counting), она выдает ошибку сегментации в строке 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

Ответ 1

Поздравляем: вы обнаружили ошибку в 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.

Ответ 2

Поставьте обратную линию. Также - какая платформа?

Это может быть ошибка, связанная с NSNumber и помеченными указателями (при нацеливании на 64-разрядную ОС X).