Forge Code

The Modern Runtime and Clang 1.6's Shadowed Variables Bug

If you’re writing code in Objective-C, and haven’t heard about the ‘@synthesize by Default’ (and to a lesser extent, ‘Ivars in Class Extensions’), you owe it to yourself to go and read up about it. Martin Pilkington describes the advantages of these new compiler/runtime features in his post New Objective-C Features. Personally, I’ve found ‘@synthesize by Default’ to be a fantastic aid to my productivity, as it means you can create or modify Obj-C properties in only one place (instead of having to keep your @property and @synthesize statements in sync).

Enabling the ‘Modern Runtime’

To enable these features, you need to be using the “Modern Runtime”, with the LLVM compiler. You should be using the LLVM compiler anyway (unless you have a good reason not to), since it’s usually faster, and it gives you much more helpful warning and error messages than GCC. In recent versions of Xcode, LLVM even shows you the exact character (not just the line) in your code where the warning or error was found.

Assuming you’re using LLVM, to enable the “Modern Runtime” and get these great new compiler/runtime features, you need to add the following to the “Other C Flags” Build Setting in Xcode:

-Xclang -fobjc-nonfragile-abi2

Now you just need to build, and everything should work…

Clang 1.6 Chokes on Shadowed Variables

If you’re like me, when you added the above Build Setting then hit “Build” in Xcode, you got an error that looked something like this:

clang: error: clang frontend command failed due to signal 11 (use -v to see invocation) Command /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang failed with exit code 245

After trying the usual places (Google, StackOverflow etc.), I went to the Apple Developer Forums. There was one thread where people described this same problem, and another one where a user proposed a cause (and hence, a solution). It turns out that Clang 1.6 (the version that ships with iOS SDK 4.2 and/or Xcode 3.2.5) has some pretty severe bugs when it comes to the Modern Runtime and shadowed variables. A shadowed variable is one that has been re-declared in a more localised scope. This code snippet shows a common example of a shadowed variable:

@property (retain) UIWebView *webView;

@synthesize webView;

- (void)webViewDidFinishLoad:(UIWebView *)webView
  NSLog(@"Web View Loaded!");

In the -webViewDidFinishLoad: method, webView refers to the method argument, even though webView was already implicitly declared as the auto-synthesized ivar that is backing the .webView property. This is known as a ‘shadowed variable’, and is relatively common in Objective-C in method parameter names. Note that if you had manually declared an ivar named webView, it would also be a shadowed variable. Unfortunately, when Clang 1.6 with the ‘modern runtime’ turned on encounters this code, it will often crash.

To work around this, you will need to get rid of the offending shadowed variables in your code. I’ve found that shadowed variables due to method parameters often cause the compiler to crash, which means you have to go through the file that caused the clang: error: clang frontend command failed due to signal 11 error and find it yourself (if the compiler actually crashes, you often won’t get a warning or error with a line number). Other shadowed variables can be found by turning on the “Hidden Local Variables” compiler warning Build Setting in Xcode. On another project, turning “Hidden Local Variables” on made Clang go into infinite recursion instead of crashing, so I got tens of thousands of warnings for each shadowed variable, which made Xcode hang for 3-4 minutes. To get around this, you can temporarily (or permanently - Peter Hosey calls it ’hardass mode’) turn on the “Treat Warnings as Errors” compiler warnings Build Setting. This will make the compiler stop before it spins out of control in infinite recursion, which should allow you to fix each shadowed variable before building again and moving onto the next one.

Once you’ve gotten rid of all the shadowed variables in your code, you should be free to make use of the language and runtime features of the Modern Runtime, like declaring your properties in a single line of code. Enjoy!