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).
Question
Post the backtrace. Also -- what platform?
It might be a bug related to NSNumber
and tagged pointers (if targeting 64 bit OS X).
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
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.
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
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.
You should file a bug report with Apple. In the meanwhile, use a strong
or unsafe_unretained
property.
Edit: 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
and run it with GDB:
$ gdb test
…
(gdb) run
The program will crash:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000000004cb
0x00007fff8ccdbacd in _CFIsDeallocating ()
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
and then the quit
command to exit GDB:
(gdb) quit
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.
Edit: this bug was fixed in OS X v10.7.3.