Objective-C - ARC - NSNumber - 分段故障

use*_*037 10 weak-references objective-c segmentation-fault nsnumber automatic-ref-counting

我有一个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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
2
Segmentation fault: 11
Run Code Online (Sandbox Code Playgroud)

小智 23

恭喜:您在Core Foundation中发现了一个错误!

比尔怀疑,这与Lion中的标记指针有关.当你创建

NSNumber *d1 = [[NSNumber alloc] initWithInteger: 4];
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

如果您阅读CFRuntime.c,您将看到_CFIsDeallocating()将相应的指针强制转换CFRuntimeBase *为读取_cfinfo.对于普通的Core Foundation对象,这是有效的,因为每个常规Core Foundation引用都指向以isa指针开头的实例,后跟_cfinfo.但是,标记指针不指向实际(已分配)内存,因此_CFIsDeallocating()尝试取消引用无效的指针,从而导致分段错误.

您应该向Apple提交错误报告.同时,使用strongunsafe_unretained属性.


编辑:获取回溯,使用-g包含调试信息构建可执行文件,例如:

$ clang test.m -g -fobjc-arc -framework Foundation -o test
Run Code Online (Sandbox Code Playgroud)

并使用GDB运行它:

$ gdb test
…
(gdb) run
Run Code Online (Sandbox Code Playgroud)

该程序将崩溃:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000000004cb
0x00007fff8ccdbacd in _CFIsDeallocating ()
Run Code Online (Sandbox Code Playgroud)

使用btGDB中的命令获取回溯:

(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
Run Code Online (Sandbox Code Playgroud)

然后quit退出GDB 的命令:

(gdb) quit
Run Code Online (Sandbox Code Playgroud)

在Xcode中,使用Mac OS X>应用程序>命令行工具模板.运行程序时,Xcode应自动在调试区域显示GDB提示.如果调试区域未显示在标准编辑器中,请选择"视图">"调试区域">"显示调试区域".


编辑:此错误已在OS X v10.7.3中修复.

  • 很好的调试工作...感谢您追求这一点,是的,请提交一个错误.我怀疑这是一个骗局,但是......以防万一...... (2认同)