Objective-C - ARC - NSNumber - Segmentation Fault

前端 未结 2 1292
旧巷少年郎
旧巷少年郎 2021-02-08 08:49

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

2条回答
  •  借酒劲吻你
    2021-02-08 09:28

    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.

提交回复
热议问题