I've already filed a radar (rdar://12311693, http://openradar.appspot.com/12311693) for the following issue, but I thought I'd post here as well to see if anyone can spot a mistake in my code that could lead to the crash.
The following code sample leads to a crash due to an over-release when built with compiler optimization turned on (-Os), but does not crash when compiler optimization is turned off (-O0). The project is being built with Xcode 4.4.1 (4F1003), Apple LLVM compiler 4.0
The app crashes when num2 is over-released. Enable Zombie Objects to confirm that this is the case.
// 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;
}
Compiler bug. Thanks for filing it.
num1
and num2
should guarantee the lifespan of the pointed-to instances. I suspect the optimizer is [correctly] reusing stack slots and [incorrectly] emitting a release/retain sequence that leads to the issue.
In response to stackmaster; it is a compiler bug. The whole point of ARC is to transition Objective-C to the point where the compiler can analyze the code with 100% certainty to know where to stick retains/releases such that you, the developer, don't have to. By and large, it can achieve exactly that, even in the face of threading, as long as both all code that uses the object in the MRR world is well behaved and the developer doesn't "escape" the object out of ARC control and do something naughty. Two big ifs, but a vast improvement over MRR.
Finally, if your code doesn't work when optimized (when no compiler bugs come into play) it is because your code is broken. A properly written optimizer does not break correctly written code.
While some compilers are notoriously buggy, LLVM is not one of them (I won't make claims about GCC because I haven't used it in years, but I'd bet the same could be said). An iOS or OS X system will executed millions and millions of lines of compiled with optimization enabled code on every boot and the system works quite well.
So, no, "the optimizer is turned on" is never the final resolution for a crash.
As Catfish_man noted, there are esoteric optimizer options that will produce technically incorrect code on purpose. They are not enabled by -Os or other "standard" optimizations. They are mostly centered on math operations and, thus, won't typically cause crashes as much as faster creep of error into calculations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With