Performing Code Analysis on your iPhone Applications

One of the key challenges faced by iPhone developers is in the area of memory management. If you are coming from an environment where memory management is all done for you via the garbage collector, the iPhone development platform could be quite a challenge to get used to.

Prior to Xcode 3.2, most developers used an open-source tool known as Clang, a source code analysis tool that finds bugs in C and Objective-C programs, to locate memory leaks in their iPhone applications. Using Clang, you could find potential code statements that could result in memory leaks, as well as find buggy code blocks that might cause runtime errors.

In Xcode 3.2, Apple has integrated Clang into the Xcode IDE, making it easily available to developers without the detailed configurations steps needed to configure Clang. This article takes you through some of the capabilities of Clang.

Memory Leaks

The most common use of Clang is to detect memory leaks in your application. For this purpose, launch Xcode and create a new View-based Application project. Name it Analyzer. In the AnalyzerViewController.m file, add the following statements in bold:
#import “AnalyzerViewController.h”@implementation AnalyzerViewController-(void) doSomething {    NSString *str = [[NSString alloc] initWithString:@”This is a string”];	}
To build the project and analyze the code at the same time, select Build’Build and Analyzer. You will see that Xcode now displays a blue-color icons containing two arrows (see Figure 1).

Figure 1. The message displayed by Clang.

It indicates that there is a potential memory leak of an object created and then stored into the variable called str. If you click on the icon, you will see the message shown in Figure 2.

Figure 2. Detailed message displayed by Clang.

The above code generates a warning because the str is allocated an NSString object, but it was never released before the method exits. To fix the problem, simply add a release statement:
-(void) doSomething {    NSString *str = [[NSString alloc] initWithString:@”This is a string”];	    [str release];}
Let’s take a look at another example. This time, code the doSomething method as follows:
-(void) doSomething {	    NSString *str = [NSString stringWithString:@”This is a string”];	    [str release];}
This time round, str is initialized with an auto-release string constant, which means that you do not own the object and hence cannot release it manually. If you now select the Build and Analyze menu item again, you will see the warning message as shown in Figure 3.

Figure 3. Incorrectly releasing an autorelease object.

To fix the error, simply remove the release statement:
-(void) doSomething {	    NSString *str = [NSString stringWithString:@”This is a string”];	    // [str release];}

Interesting Things about Strings

Dealing with strings in Objective-C is sometimes like opening a Pandora box – you never know what you are going to get. Consider the following example:
#import “AnalyzerViewController.h”@implementation AnalyzerViewController-(void) doSomething {    NSString *str = [[NSString alloc] initWithString:@”This is a string”];	    str = [[NSString alloc] initWithString:@”This is another string”];	    [str release];}
Look at the code above carefully. Is there a memory leak? Now, select the Build and Analyze menu item and see the result of the analysis. You should see the result shown in Figure 4.

Figure 4. Clang detecting a potential memory leak.

In fact, there is a memory leak. The first statement assigns str to an NSString object. And the second statement allocates another instance of the NSString object. The release statement releases the second NSString object. However, the first NSString object is leaked and it will never be recovered. Hence there is a memory leak. Consider a slightly changed version of the same code:
-(void) doSomething {    NSString *str = [[NSString alloc] initWithString:@”This is a string”];	    str = [[NSString alloc] initWithString:@”This is a string”];	    [str release];}
If you get the compiler to analyze the code again, notice that it will continue to sound off a warning about potential memory leaks. However, observe carefully that both strings now contain the same string constant. When two objects have the same string constant, the compiler will assign the two variables to point to only one instance. To verify this, you can print out the address of the two variables, like this:
-(void) doSomething {    NSString *str = [[NSString alloc] initWithString:@”This is a string”];     NSLog(@”%d”, str);    str = [[NSString alloc] initWithString:@”This is an string”];     NSLog(@”%d”, str);    [str release];}
If you were to run the above code, you will see that the address is the same for both. If you change the two strings to be different, you would then see different addresses.

Hence, to conclude, in this case, if the two strings are the same, there will be no memory leaks. In general, it is wise to be careful about such cases and follow the rule-of-thumb for memory management in Objective-C – release whenever you use an alloc.

Let’s consider another example:
-(void) doSomething {    NSString *str2;    for (int i = 0; i < 50; i++){        NSString *str1 = @"This is a constant string";        str2 = [[NSString alloc] initWithString:str1];    }    [str2 release];}
When you analyze the code, you will see the message as shown in Figure 5.

Figure 5. Clang sounding a memory leak warning.

Again, in this case there is no memory leak. The str1 object is an auto-release object while str2 always get assigned the same string constant. Printing out the addresses of str1 and str2 confirms this:
-(void) doSomething {    NSString *str2;    for (int i = 0; i < 50; i++){        NSString *str1 = @"This is a constant string";        NSLog(@"str1 address is %d", str1);	        str2 = [[NSString alloc] initWithString:str1];        NSLog(@"str2 address is %d", str2);    }    [str2 release];}
Figure 6 shows the output observed in the Debugger Console window.

Figure 6. The addresses of the objects as printed out in the Debugger Console window

Unused Objects/Variables

Besides using Clang for static code analysis, you can also use it to detect unused variables and objects. The following code is one such example:
-(int) addNum:(int) num1 toNum:(int) num2 {    return (num1 + num2);	}-(void) doSomething {    int result;    result =[self addNum:5 toNum:6];	}
When analyzed, Clang will warn you that the variable result is never used (see Figure 7).

Figure 7. Clang warning about unused variables.

Uninitialized Variables

Another potential bug that the Clang can catch is uninitialized variables. Consider the following example:
-(int) makeDecision:(int) num {    int val;    if (num>0)         val = 99;    else if (num<0) {        val =  -99;    }    return val;}
If num is equal to 0, you will have a problem with val since it has not been initialized. Running Clang will flag the warning as shown in Figure 8.

Figure 8. Clang warning about uninitialized variable.

Project Settings

If you want Clang to automatically analyze your code every-time you build your project, you can do by modifying the project settings in Xcode. In Xcode, select your project and click on the Info button (located at the top of the toolbar). Click on the Build tab and scroll down the list. Under the Build Options section, check the Run Static Analyzer options (see Figure 9).

Figure 9. Configuring Xcode to analyze your code every time you build the project

Summary

In this article, you have seen the use of Clang within Xcode to analyze your code for potential memory leaks and logic errors. Now that you have seen how easy it is to use, there is no reason for you not to use it in your next project!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: