使用-Os在objc ARC下过度释放,但不使用-O0

And*_*ger 10 objective-c llvm automatic-ref-counting

我已经提交了雷达(rdar:// 12311693,http://openradar.appspot.com/12311693)以下问题,但我想我会在这里发布,以及看看是否有人能发现在一个错误我的代码可能会导致崩溃.

以下代码示例由于在打开编译器优化(-Os)时构建过度而导致崩溃,但在关闭编译器优化(-O0)时不会崩溃.该项目正在使用Xcode 4.4.1(4F1003),Apple LLVM编译器4.0构建

当num2过度释放时,应用程序崩溃.启用Zombie Objects以确认是这种情况.

// This crashes under -Os, but not under -O0
NSNumber *num1 = @((float)arc4random() / (float)UINT32_MAX);
NSNumber *num2 = @((float)arc4random() / (float)UINT32_MAX);

NSNumber *foo1 = num1;
NSNumber *foo2 = num2;

for (NSUInteger i=0; i<2; i++) {

    NSLog(@"foo1: %p %@", foo1, foo1);
    NSLog(@"foo2: %p %@", foo2, foo2);

    // swap foo1 and foo2
    foo1 = num2;
    foo2 = num1;
}
Run Code Online (Sandbox Code Playgroud)

bbu*_*bum 6

编译器错误.谢谢你提交.

num1num2应保证指向实例的生命周期.我怀疑优化器[正确]重用堆栈槽并[错误地]发出导致问题的释放/保留序列.


响应stackmaster; 这是一个编译器错误.ARC的重点是将Objective-C转换到编译器可以100%确定地分析代码的位置,以便了解保留/发布的位置,这样您,开发人员就不必这样做.总的来说,即使面对线程,它也可以实现这一点,只要在MRR世界中使用对象的所有代码都表现良好并且开发人员不会将对象"逃离"ARC控制和做一些顽皮的事.两个大的问题,但比MRR有很大的改进.

最后,如果您的代码在优化时不起作用(当没有编译器错误发挥作用时),那是因为您的代码被破坏了.正确编写的优化器不会破坏正确编写的代码.

虽然有些编译器是出了名的错误,但LLVM并不是其中之一(我不会对GCC提出任何要求,因为我多年没有使用它,但我敢打赌也可以这么说).iOS或OS X系统将在每次启动时执行数百万行编译并启用优化代码,系统运行良好.

所以,不,"优化器打开"永远不是崩溃的最终解决方案.


正如Catfish_man所指出的那样,有一些深奥的优化器选项故意产生技术上不正确的代码.它们不是由-Os或其他"标准"优化启用的.它们主要集中在数学运算上,因此,通常不会导致崩溃,因为错误会更快地发生在计算中.

  • @stackmonster:除了未定义的行为和(某些)实现定义的行为之外,优化器应该构建的代码行为与写入的行为相同(对于外部观察者).在发布的代码中导致过度发布的东西肯定是一个错误. (5认同)
  • @stackmonster如果您的代码在启用优化时中断,您可能希望开始处理代码.特别是如果它的"吨"破裂. (3认同)
  • @stackmonster ARC不仅仅是编译器的一个特性吗? (2认同)
  • @stackmonster你编写的内容完全错误.优化不是借口. (2认同)
  • 如果您不依赖于未定义的行为,则破坏程序的优化是不正确的优化.如果您依赖于未定义的行为,则您的程序不正确.当然,一些优化是故意不正确的(例如,某些东西由-ffast-math打开),但默认情况下这些不是开启的. (2认同)