我有一个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
答案 0 :(得分:23)
恭喜:您在Core Foundation中发现了一个错误!
比尔怀疑,这与tagged pointers in 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()
会尝试取消引用无效的指针,因此会出现分段错误。
你应该file a bug report with 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 ()
使用GDB中的bt
命令获取回溯:
(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&gt;申请&gt;命令行工具模板。运行程序时,Xcode应自动在调试区域显示GDB提示。如果调试区域未显示在标准编辑器中,请选择查看&gt;调试区域&gt;显示调试区域。
编辑:此错误已在OS X v10.7.3中修复。
答案 1 :(得分:0)
发布回溯。还 - 什么平台?
这可能是与NSNumber
和标记指针相关的错误(如果定位到64位OS X)。