This is a known bug and is has been submitted to bugreporter.apple.com under bug id #16040090
NB: This issue only reproducible on a 64-bit (A7) iOS device. If run in the simulator or on a 32-bit device it works fine.
Please note: This bug seems to be fixed in LLVM 5.1, this is the default compiler for Xcode 5.1 (currently in beta).
I have a method -pointValue
(see below), it works fine when compiled with the optimisation level set to -O0
, but using -Os
(the default for Release builds) the compiler optimises out the line that sets the variable point
. point
is used as the return value so any other method calling this gets random values.
The issue can be fixed by declaring the points
variable as volatile
. However, why does the compiler think it can remove the line setting points
? Is it something to do with how I have written the method?
- (CGPoint)pointValue
{
ULongLong encodedPoint = [self unsignedLongLongValue];
ULongLong *values = [self splitEncodedInteger:encodedPoint withShift:SHIFT];
//volatile is required to prevent optimising out
volatile CGPoint point = CGPointMake(values[0], values[1]);
free(values); //clean up
return point;
}
NB: -splitEncodedInteger:withShift:
uses malloc() to create a 2 element array that is retuned and then this memory is free
'd by the callee.
As requested, the code for -splitEncodedInteger:withShift:
- (ULongLong *)splitEncodedInteger:(ULongLong)encocedInteger withShift:(int)shiftValue
{
ULongLong *splitFloats = malloc(sizeof(ULongLong) * 2);
splitFloats[0] = (encocedInteger >> shiftValue);
splitFloats[1] = encocedInteger - ((encocedInteger >> shiftValue) << shiftValue);
return splitFloats;
}
Full source code of the encode categories can be found on GitHub.
As requested by several commenters I have created a simple test project. However, even after setting all the build settings to match the original project I myself cannot reproduce the issue. The bug only shows up on device.
The only thing I can see different is when the project is run with full optimisation on, LLDB can read some of the variables, and trying to print them to the console I get this:
(CGSize) size = <no location, value may have been optimized out>
This is exactly what I get with my failing project but in that instance passing around one of these "optimised out" variables just gives random data (resulting in massive views being created [or failing to be created]).
Below are screen shots of the example app running with -O0 and -Ofast respectively.
Example app running with -O0 (no optimisations), you can see info on the variables
Example app running with -Ofast (full optimisations), you cannot see info on the variables
This is the output when running ton device with optimisations off:
2014-02-10 11:36:00.771 optimisation-bug[461:60b] *** Compiling with no optmisations, the code should work as expected ***
2014-02-10 11:36:00.773 optimisation-bug[461:60b] encodedRect: 50332672
2014-02-10 11:36:00.774 optimisation-bug[461:60b] encodedSize: 45089712
2014-02-10 11:36:00.775 optimisation-bug[461:60b] encodePoint: 2621480
2014-02-10 11:36:05.629 optimisation-bug[461:60b] rect: {{0, 0}, {768, 1024}}
2014-02-10 11:36:06.099 optimisation-bug[461:60b] size: {688, 944}
2014-02-10 11:36:06.101 optimisation-bug[461:60b] point: 40.000000, 40.000000
2014-02-10 11:36:06.103 optimisation-bug[461:60b] DONE
This is the output when running on device with full optimisations:
2014-02-10 11:44:53.975 optimisation-bug[471:60b] >>> Compiling with -Os optmisations, the code should *NOT* work as expected <<<
2014-02-10 11:44:53.977 optimisation-bug[471:60b] encodedRect: 50332672
2014-02-10 11:44:53.977 optimisation-bug[471:60b] encodedSize: 45089712
2014-02-10 11:44:53.978 optimisation-bug[471:60b] encodePoint: 2621480
2014-02-10 11:44:58.176 optimisation-bug[471:60b] rect: {{1.3464973428307575e+19, 6174053600}, {1.3464973428307575e+19, 1.2554206452792682e+58}}
2014-02-10 11:44:58.178 optimisation-bug[471:60b] size: {1.3464973428307575e+19, 6174053568}
2014-02-10 11:44:58.180 optimisation-bug[471:60b] point: 13464973428307574784.000000, 6174053568.000000
2014-02-10 11:44:58.182 optimisation-bug[471:60b] DONE
This issues seems to be a bug in the arm64 compiler; armv7(s) and x86 (Simulator) run the code without issue.
- (CGPoint)pointValue
{
ULongLong encodedPoint = [self unsignedLongLongValue];
ULongLong *values = [self splitEncodedInteger:encodedPoint withShift:SHIFT];
//volatile is required to prevent optimising out
/*volatile*/ CGPoint point = CGPointMake(values[0], values[1]);
free(values); //clean up
return point;
}
What seems to be happening is the free(values)
line is being reordered in the optimisation phase and run before CGPointMake(...)
causing pointer
to return with garbage values.
Thanks to Mike Ash, CRD and Rob Napier.
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