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
1) Why does the segmentation fault occur ?
Given below is the program:
#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);
}
Output:
1
2
Segmentation fault: 11
Congratulations: you’ve found a bug in Core Foundation!
As Bill suspected, this is related to tagged pointers in Lion. When you create
d1doesn’t point to an actualNSNumberinstance. Instead,d1is a tagged pointer containing0x4c3, where0x4is 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
-allowsWeakReferenceto the instance to verify whether it can be used as a weak reference. SinceNSNumberdoesn’t override that method, the default implementation inNSObjectis executed, which in turn sends_isDeallocating, which in turn calls_CFIsDeallocating()as shown in this stack trace:If you read CFRuntime.c, you’ll see that
_CFIsDeallocating()casts the corresponding pointer toCFRuntimeBase *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 theisapointer, 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
strongorunsafe_unretainedproperty.Edit: to get the backtrace, build your executable with
-gto include debug information, e.g.:and run it with GDB:
The program will crash:
Use the
btcommand in GDB to get the backtrace:and then the
quitcommand to exit 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.
Edit: this bug was fixed in OS X v10.7.3.