在范围内创建的对象即使在范围之外使用也会被释放

Mat*_*man 13 objective-c llvm clang automatic-ref-counting

更新:这已在iOS 6.1 DP3 SDK中修复.

我使用默认版本构建配置使用ARC构建时,我已经跟踪了一个使用后释放崩溃(调试似乎工作正常).在具有非常量条件的if-scope中创建对象,将其分配给范围外部的变量,然后仅使用Objective-C数组或字典文字引用该变量时,会发生此问题.

这是我设法找到的最小的可重复的案例:

void test(BOOL arg)
{
    id obj = nil;

    if (arg) {
        obj = [NSObject new];
    }

    // obj already deallocated here
    @[obj];

    // but using NSArray works
    //[NSArray arrayWithObject:obj];

    // @[obj] works if obj is referenced i.e. by NSLog print out
    //NSLog(@"%@", obj);
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        test(YES);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我使用zombie对象构建并运行它时,我收到以下错误消息:

-[NSObject retain]: message sent to deallocated instance 0x100109100
Run Code Online (Sandbox Code Playgroud)

正如我在代码中评论的那样,如果obj以其他方式引用它,它可以正常工作,例如使用NSLog或使用NSArray.我是否误解了如何使用ARC和作用域释放对象,或者这是LLVM或Clang中的优化错误?

我正在使用Xcode 4.5.2和clang 4.1版(标签/ Apple/clang-421.11.66)(基于LLVM 3.1svn).我可以在为iOS模拟器和Mac OS X构建x86 64位时重现它,我很确定在为ARM构建时出现同样的问题,因为在iPhone上运行发布版本时首次发现该问题.

我已向Apple提交了错误报告,并制作了一份开放式雷达报告.

什么,如果有的话,我错过了什么?

更新,做了一些实验:

正如Gabro指出编译器转换@[][NSArray arrayWithObjects:count:]语句所以我做了一些测试:

// works
id a[] = {obj};
[NSArray arrayWithObjects:a count:1];

// does not work
const id *b = (id[]){obj};
[NSArray arrayWithObjects:b count:1];

// does not work
[NSArray arrayWithObjects:(id[]){obj} count:1];
Run Code Online (Sandbox Code Playgroud)

所以我的猜测是,当组合ARC和匿名C数组时会发生这种情况.

Gab*_*lla 1

我刚刚测试了针对 OSX (x86 64) 和 iOS Simulator 构建的以下代码,但无法重现该错误

 void test(BOOL arg) {
     id obj = nil;

    if (arg) {
        obj = [NSObject new];
    }
    @[obj];
    NSLog(@"Hi there");
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        test(YES);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码只是Hi there在控制台中打印并返回。

我的配置与你的相同:XCode 4.5.2 和 Apple clang 版本 4.1 (tags/Apple/clang-421.11.66) (基于 LLVM 3.1svn) 作为编译器。

编辑

我还尝试使用命令行进行编译(#include <Foundation/Foundation.h> 在上面示例的开头添加之后)

clang -fobjc-arc -framework Foundation main.m
Run Code Online (Sandbox Code Playgroud)

结果又是

2012-12-03 12:47:45.647 a.out[39421:707] Hi there
Run Code Online (Sandbox Code Playgroud)

编辑2 正如评论中所指出的,可以重现增加优化级别的错误-O0。总结:

clang -O0 -fobjc-arc -framework Foundation main.m
Run Code Online (Sandbox Code Playgroud)

该程序按预期运行

clang -O1 -fobjc-arc -framework Foundation main.m
Run Code Online (Sandbox Code Playgroud)

问题中提出的错误出现了。对于超过任何优化级别都是如此-O0

这绝对是编译器中的一个错误。