Coding

Sanitizers, The Alternative To Valgrind

Valgrind is an incredibly powerful tool which helps find leaks, buffer overflows and many other things. Whilst being extremely powerful it can also be very slow. As an alternative there are little known tools that are available for Clang and GCC which can fulfil similar functions for your C / C++ applications but with much higher performance.

I’ve had several people ask me about the sanitizers recently and how to use them, so I’ll cover some basics here.

Instead of being something that is executed at runtime like Valgrind, the sanitizers are linked to your applications at build time. So your build system would normally have a way to enable this mode to use during testing and on a Continuous Integration system. It is worth noting that you should not try to link two sanitizers at the same time.

The sanitizers were originally part of the LLVM/Clang project but were soon ported to work with GCC as well. I personally still use Clang when using them, but you should use whatever you feel comfortable with. As with most debugging style tools you will get better results with more optimizer flags disabled. The sanitizer authors recommend -O1 as a good compromise.

Address Sanitizer

The Address Sanitizer (asan for short) is very similar to Valgrind’s default “memcheck” tool. It basically checks for bad memory usage such as buffer overflows as well as leaks. It has a performance penalty of roughly 2x, which whilst it is a large impact is still significantly better than Valgrind. You may need to install the package libasan on your Linux distribution of choice.

You build with the flag -fsanitize=address, if you are using C++ then it is worth setting -fno-omit-frame-pointer too as you will get better results. As an example taken from Clang’s documentation, create the file example_UseAfterFree.cc:

int main(int argc, char **argv) {
  int *array = new int[100];
  delete [] array;
  return array[argc];  // BOOM
}

Compile this with:

clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc

When you run the resulting ./a.out you will get:

If you don’t get line numbers in the output you will need to install llvm-symbolizer. In most Linux distributions this is provided in the “llvm” package.

Thread Sanitizer

The Thread Sanitizer (tsan for short) is designed to find race conditions in your code, very similar to the “Helgrind” tool in Valgrind. It has a typical slowdown of 5x – 15x and a memory overhead of 5x – 10x. Very much like the Address Sanitizer you compile it in using a simple flag, -fsanitize=thread. You should not try to use this with the asan flag. This won’t compile. Again from the Clang manual this is tiny_race.c:

#include <pthread.h>
int Global;
void *Thread1(void *x) {
  Global = 42;
  return x;
}
int main() {
  pthread_t t;
  pthread_create(&t, NULL, Thread1, NULL);
  Global = 43;
  pthread_join(t, NULL);
  return Global;
}

Then compile with:

clang -fsanitize=thread -g -O1 tiny_race.c

This may take a few attempts to execute to trigger but you will end up with:

Undefined Behaviour Sanitizer

The Undefined Behaviour Sanitizer (ubsan for short) does exactly what it says on the tin, it detects undefined behaviour usage in your application that can lead to bugs and portability issues and it is extremely fast. There are a whole bunch of different options to turn on here but the ones I typically use are -fsanitize=undefined -fsanitize=nullability. Another example from the Clang manual:

int main(int argc, char **argv) {
  int k = 0x7fffffff;
  k += argc;
  return 0;
}

Compile with:

clang++ -fsanitize=undefined ubsan_test.cc

When you execute this you will see:

Summary

This is just a basic introduction to the available sanitizers, they have many more features and there are several more available. They should definitely be part of a testing regime for any C / C++ codebase.

Featured Image by Marco Verch used under a CC BY 2.0 license

LinuxJedi

View Comments

  • Thanks for this. I've been using Valgrind up to now, but it slows the application down so much that it becomes virtually unusable. I'd heard of sanitizers quite by chance, and linking to asan has made life much easier (and picked up things that valgrind didn't).

Share
Published by
LinuxJedi
Tags: COpen Source

Recent Posts

Diagnosing an Amiga 1200 Data Path Fault

I recently acquired an Amiga 1200 motherboard in a spares/repairs condition for about £100 recently.…

2 days ago

Bare Metal “Hello World” on an STM32MP135F-DK

Whilst I do like working with STM32 development boards, some basic information I need can…

3 days ago

Two special Amiga 4000s: Diagnosing Jops

When I last left this blog series, the first of Stoo Cambridge's A4000s had gone…

6 days ago

Joining wolfSSL

At the beginning of November, I started working for wolfSSL. Now that I'm a week…

1 week ago

Two special Amiga 4000s: Rebuilding Jools

In my previous post, I had the Amiga 4000 known as Jools mostly repaired, there…

4 weeks ago

Two special Amiga 4000s: Repairing Jools

In my last post, I created a list of things I needed to repair on…

4 weeks ago