【问题标题】:Objective-C - ARC - NSNumber - Segmentation FaultObjective-C - ARC - NSNumber - 分段错误
【发布时间】:2011-12-28 20:36:51
【问题描述】:

我有一个 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

【问题讨论】:

  • 这给出了 KERN_INVALID_ADDRESS,看起来像是总线错误而不是分段错误。
  • 只是好奇,为什么你使用 printf() 而不是 NSLog()?
  • 我刚接触 Objective-C,所以我倾向于使用 printf

标签: objective-c segmentation-fault automatic-ref-counting nsnumber weak-references


【解决方案1】:

发布回溯。还有——什么平台?

这可能是与NSNumber 和标记指针相关的错误(如果针对 64 位 OS X)。

【讨论】:

  • 我自己试过了,它在_CFIsDeallocating() 内部崩溃了。我在想它看起来也像一个带有标记指针的错误。
【解决方案2】:

恭喜:您在 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。同时,使用strongunsafe_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 > 应用程序 > 命令行工具模板。当你运行你的程序时,Xcode 应该会在调试区域自动显示 GDB 提示符。如果调试区域未显示在标准编辑器中,请选择查看 > 调试区域 > 显示调试区域。


编辑:此错误已在 OS X v10.7.3 中修复。

【讨论】:

  • 非常感谢大家,非常有帮助和详细的解释。
  • 很好的调试工作...感谢您的努力,是的,请提交错误。我怀疑这是一个骗局,但是……以防万一……
  • 如何打印跟踪(clang-ARC)?我从命令行使用它。我想知道如何在命令行上打印跟踪以及当我使用 X-Code 时我应该怎么做?
  • 不知何故我无法登录您之前提供的苹果链接报告错误
  • 您需要一个注册的开发者帐户(免费或付费)。不过,过去几天错误报告网站一直不稳定,所以请继续努力!
猜你喜欢
  • 2022-01-16
  • 2013-02-19
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-10
  • 2014-03-22
相关资源
最近更新 更多