问题描述
我有一个 Objective-C 程序,我正在使用 ARC(自动引用计数),它在第 23 行引发了分段错误(参见下面的程序).
I have an objective-C program and I am using ARC (Automatic Reference Counting), it throws a segmentation fault in line 23 (see program below).
问题1)为什么会出现分段错误?
Question 1) Why does the segmentation fault occur ?
下面是程序:
#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
");
NSNumber *d1 = [[NSNumber alloc] initWithInteger: 4];
printf("2
");
car1.doors = d1; //Segmentation fault.. why ?
printf("3
");
}
printf("---- end
");
return(0);
}
输出:
1
2
Segmentation fault: 11
推荐答案
恭喜:您在 Core Foundation 中发现了一个错误!
Congratulations: you’ve found a bug in Core Foundation!
正如比尔所怀疑的,这与 标记的指针有关狮子.当你创建
As Bill suspected, this is related to tagged pointers in Lion. When you create
NSNumber *d1 = [[NSNumber alloc] initWithInteger: 4];
d1
并不指向实际的 NSNumber
实例.相反,d1
是一个包含 0x4c3
的标记指针,其中 0x4
是标记指针中的有效负载.
d1
doesn’t point to an actual NSNumber
instance. Instead, d1
is a tagged pointer containing 0x4c3
, where 0x4
is the payload in the tagged pointer.
当您尝试使用标记指针作为弱属性的值时,Objective-C 运行时执行的步骤之一是向实例发送 -allowsWeakReference
以验证它是否可以用作弱参考.由于 NSNumber
没有覆盖该方法,所以执行 NSObject
中的默认实现,然后发送 _isDeallocating
,然后调用 >_CFIsDeallocating()
如此堆栈跟踪所示:
When you try to use a tagged pointer as the value of a weak property, one of the steps executed by the Objective-C runtime is to send -allowsWeakReference
to the instance to verify whether it can be used as a weak reference. Since NSNumber
doesn’t override that method, the default implementation in NSObject
is executed, which in turn sends _isDeallocating
, which in turn calls _CFIsDeallocating()
as shown in this stack trace:
#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,您会看到 CFRuntime.ccode>_CFisDeallocating() 将相应的指针转换为 CFRuntimeBase *
以便读取 _cfinfo
.对于普通的 Core Foundation 对象,这是可行的,因为每个常规的 Core Foundation 引用都指向一个以 isa
指针开头的实例,然后是 _cfinfo
.但是,标记的指针并不指向实际(分配的)内存,因此 _CFIsDeallocating()
会尝试取消引用无效的指针,从而导致分段错误.
If you read CFRuntime.c, you’ll see that _CFIsDeallocating()
casts the corresponding pointer to CFRuntimeBase *
in order to read _cfinfo
. For normal Core Foundation objects, this works because every regular Core Foundation reference points to an instance that starts with the isa
pointer, followed by _cfinfo
. However, tagged pointers do not point to actual (allocated) memory, so _CFIsDeallocating()
tries to dereference a pointer that is not valid, hence the segmentation fault.
您应该向 Apple 提交错误报告.同时,使用 strong
或 unsafe_unretained
属性.
You should file a bug report with Apple. In the meanwhile, use a strong
or unsafe_unretained
property.
要获取回溯,请使用 -g
构建可执行文件以包含调试信息,例如:
to get the backtrace, build your executable with -g
to include debug information, e.g.:
$ clang test.m -g -fobjc-arc -framework Foundation -o test
并使用 GDB 运行它:
and run it with 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
命令获取回溯:
Use the bt
command in GDB to get the backtrace:
(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 提示符.如果调试区域未显示在标准编辑器中,请选择查看 > 调试区域 > 显示调试区域.
In Xcode, use the Mac OS X > Application > Command Line Tool template. When you run your program, Xcode should automatically show the GDB prompt in the debug area. If the debug area doesn’t show up in the Standard Editor, select View > Debug Area > Show Debug Area.
此错误已在 OS X v10.7.3 中修复.
this bug was fixed in OS X v10.7.3.
这篇关于Objective-C - ARC - NSNumber - 分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!