Navigation
Other Sites
My Stuff:
Search
Twitterings
Friday
03Apr2009

Git pre-commit hooks and the Clang Static Analyzer

For the solo developer, it's easy to kid yourself into believing that you'll run those tests "when appropriate". It never really happens, does it?

I've always liked the Clang Static Analyzer as a tool for finding code oversights, but I've always found it a bit annoying to run. I always forgot the options, or something didn't quite work as expected. That's really my fault, rather than CSA's.

Anyway, it occurred to me that I could use my tools to keep myself more honest about regularly running the static analyzer. I use Git for source control and Git provides a pre-commit hook feature. The idea of pre-commit hooks is that you get to run a script before the commit happens. Depending on the result code of the script, the commit will either proceed or be aborted.

I wrote a wrapper around the scan-build tool, so that I could run the analyzer by hand with my preferred options at any time:


#!/bin/sh
~/Scripts/clang/latest/scan-build --status-bugs \
-warn-objc-missing-dealloc \
xcodebuild -sdk iphonesimulator2.2.1 -configuration Debug


The --status-bugs flag is the trick here: it makes scan-build return a non-zero status code if it detects bugs. That's what we want with Git pre-commit hooks: a non-zero status indicates a possible bug, and that causes the Git commit to be aborted.

Also, I think I'm right in saying that you can't run the static analyzer on ARM code, hence the use of the iPhone Simulator SDK.

The pre-commit hook is a script at .git/hooks/pre-commit in your repository. There's an example file in every .git/hooks that you can copy and edit. Because I wrote my wrapper script above, the pre-commit is trivial:


[(master)]$ cat .git/hooks/pre-commit
#!/bin/sh
./clang.sh


The working directory for the pre-commit script is the parent directory of your .git directory.

[Update: Peter Hosey tells you how to do this for Mercurial]

Reader Comments (8)

Nice idea. Do you find this slows commits down to unacceptable levels now though?

April 3, 2009 | Unregistered CommenterJonathan Wight

This does seem to be a reasonable way to keep you honest, but I could also see this negatively affecting your use of the repository. What happens when you are done for the day, you go to commit and the commit fails because of bugs in the code? You either sit down a fix them (not really an option if there was a reason you called it quits), remove the hook (a pain, and you just subverted your test), or you just don't commit (easiest, but also the most dangerous. Personally, I believe in very frequent commits, and I'm leery of anything that would break me of the habit. I'd also argue that the point when you go bug hunting is precisely the point you want a current copy in the repository in case you break something in the process and need to revert.

April 3, 2009 | Unregistered CommenterBlack

I'd offer the addition of '-k -V' to the scan-build options, so scan-view will automatically launch in your browser of choice if bugs are found.

In other words:

~/Scripts/clang/latest/scan-build --status-bugs \
-warn-objc-missing-dealloc \
-k -V \
xcodebuild -sdk iphonesimulator2.2.1 -configuration Debug

April 3, 2009 | Unregistered CommenterOwain Hunt

I agree with Black, there are plenty of times when you want to commit something you haven't finished work on. It's a bit like setting your tests to run when you build - a nice idea, but in practice, I always end up turning it off.

What would make more sense to me would be to automatically scan-build pre-push, as in, before you share your changes with your team / the world.

April 3, 2009 | Unregistered CommenterBen Copsey

Thanks for writing this up. I've been meaning to try Clang Static Analyzer, integrating it with git seems like a good idea.

April 5, 2009 | Unregistered CommenterMarc Charbonneau

I've used Clang Static Analyzer for quite some time, and it has saved me numerous memory leaks (and I regard myself as an experienced Cocoa programmer).

I've incorporated it into my project by making a Shell Script Target. This way I dont have to remember all the parameters, and I can run it at my leisure simply by right-clicking the target and select Build.

April 7, 2009 | Unregistered CommenterJoachim Bondo

The problem with adding -warn-objc-missing-dealloc seems to be that it turns off the other checks (running it with -h also says that). When I run it without that option, I get a bunch of warnings that I don't get with it. Is there a way to specify all checks without having to list them separately?

April 7, 2009 | Unregistered CommenterRobert Kosara

Another problem with -warn-objc-missing-dealloc is that it won't find releases that are performed outside dealloc, say if your dealloc contains a line [self releaseOutlets];. I'd expect a static analyzer to be able to follow a simple message call, but apparently not. Are the semantics of Objective-C such that this is impossible?

The solution is to use an ugly macro.

April 10, 2009 | Unregistered CommenterSteve Weller

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>