Marek Felšöci

Using AddressSanitizer (ASan) in a CMake project

AddressSanitizer (ASan) [1] is a memory error detector for the C and C++ languages. It has been included in compilers such as GCC and Clang for quite some time now. Although the official Wiki page provides a very straightforward guide on how to use ASan in a general case, I could not find a good example of ASan being used in a CMake project. This is what this post is about.

Example project

Throughout this post I rely on a short example project ASanDemo coded in C. It implements two functions (see files asan-demo.h and asan-demo.c) used in such a way as to trigger errors in ASan (see file main.c).

The project has the following file structure.

ASanDemo
├── build
├── include
│   └── asan-demo.h
├── src
│   ├── asan-demo.c
│   └── main.c
└── CMakeLists.txt

Implementation

C source code

Header file

The header file asan-demo.h defines two functions:

  1. multiply, a simple 32-bit integer multiplication function to demonstrate an integer overflow error,
#ifndef __ASAN_DEMO_H
#define __ASAN_DEMO_H

#include <stdio.h>
#include <stdlib.h>

int multiply(int, int);
  1. leaker, a function that allocates memory but does not free it before returning.
void leaker(void);

#endif

Sources

Then, the associated source file asan-demo.c implements these functions.

#include "asan-demo.h"

int multiply(int a, int b) {
  return a * b;
}

void leaker(void) {
  void * buffer = malloc(256);
}

Finally, from the main function in main.c, I call both of the functions in such a way as to trigger errors in ASan.

#include "asan-demo.h"

int main(void) {
  // 32-bit integer overflow
  int result = multiply(4000000, 4000000);
  printf(
    "4,000,000 x 4,000,000 -> %d (computed) vs. 16,000,000,000,000 "
    "(expected)\n", result
  );

  // Memory leak
  leaker();

  return 0;  
}

CMake build configuration

There comes the most interesting part of the post, the CMake build configuration of our small example project.

I begin by defining the minimum CMake version required for the project.

cmake_minimum_required(VERSION 3.1)

Then, I declare the project itself.

project(asan-demo C)

The HEADERS and SRC variables shall hold the paths to all the header and source files respectively.

set(HEADERS
  "include/asan-demo.h"
)
set(SRC
  "src/asan-demo.c"
  "src/main.c"
)

I instrument the compiler (GCC in this case) to produce an executable called asan-demo from the sources listed above.

add_executable(asan-demo ${SRC} ${HEADERS})

I also need to add include to the list of include folders of the project.

target_include_directories(asan-demo PUBLIC "include")

Eventually, I enable ASan if the build type is set to Debug. I do not want to use ASan in the final release as it may degrade the application's performance.

The compilation and linking options associated to ASan here are:

  • -fsanitize=undefined enabling the detection of undefined behavior such as integer overflows,
  • -fsanitize=address enabling the detection of memory problems such as leaks.

See [1] for additional information about the possibilities of the tool.

if(CMAKE_BUILD_TYPE MATCHES "Debug")
  set(
    CMAKE_C_FLAGS
    "${CMAKE_C_FLAGS} -Werror -fsanitize=undefined -fsanitize=address"
  )
  target_link_options(asan-demo
    BEFORE PUBLIC -fsanitize=undefined PUBLIC -fsanitize=address
  )
endif()

Download, build and test

You can download the source files of the example project either separately or all at once (including the folder structure) as a tarball via the links below.

Ensure you have restored the file structure of the project as described in Section Example project, navigate to the build folder and run the following commands to configure, build and execute the project.

cmake -DCMAKE_BUILD_TYPE="Debug" ..
make
./asan-demo

To configure the project without ASan, change the build type to something else than Debug, e.g. Release.

cmake -DCMAKE_BUILD_TYPE="Release" ..

Note that, Release is also the default build type.

cmake ..

Miscellaneous

As a side note, I use the ELisp code below to tangle (extract) the source code from this post, produce the output C and CMake source files and create the tarball containing the entire example project at the end.

(require 'org)
(org-babel-tangle-file "using-address-sanitizer-asan-in-a-cmake-project.org")
(shell-command "tar -cvJf ./attachments/ASan.tar.xz ./attachments/ASan") 

References

[1]
“AddressSanitizer.” https://github.com/google/sanitizers/wiki/AddressSanitizer.

Last update on 18/08/2022


This site is proudly powered by Org mode for Emacs on the servers of Websupport, spol. s r. o.

Source code of the site is publicly available on GitHub.

Featured icons come from the open-source sets Chicago95 and flag-icons.

Content is available under the Creative Commons BY NC ND 4.0 International license unless otherwise stated.

Creative Commons License