Under Development
stars

Address Sanitizer#

Check for memory leaks, buffer overflows, etc

Note: Running a program using ASAN will consume more memory and run more slowly than normal.

The Address Sanitizer adds compile-time options that can detect:

  • Memory leaks

  • Buffer overflows (and underflows)

  • Out-of-bounds accesses to heap, stack and globals

  • Memory use after free

  • Double-free, invalid free

Installation#

First you may need to install the ASAN libraries.

  • Debian: apt-get install libasan6

  • Fedora: dnf install libasan

Building#

To build NeoMutt with the Address Sanitizer, you need to add a option to the compiler and linker. The simplest way is to:

./configure --asan [OPTIONS]
make

Alternatively, you can specify additional build flags:

export EXTRA_CFLAGS="-fsanitize=address"
export EXTRA_LDFLAGS="-fsanitize=address"
./configure [OPTIONS]
make

When debugging, it may also be helpful to add:

EXTRA_CFLAGS="$EXTRA_CFLAGS -ggdb3 -O0"

Address Sanitizer Options#

The Address Sanitizer’s behaviour can be controlled by setting an environment variable. Multiple options should be separated with a colon :

Note: Some platforms will need to use this options to show memory leaks:

export ASAN_OPTIONS="detect_leaks=1"

This highly recommended option redirects the output to a file (ncurses can cause the output become garbled).

This will create a file called asan.PROCESS_ID

export ASAN_OPTIONS="log_path=asan"

This option reduces the clutter in the output:

export ASAN_OPTIONS="print_legend=0"

Here are multiple options together, separated by colon :

export ASAN_OPTIONS="print_legend=0:log_path=asan"

For a fuller list of options, see

Running NeoMutt#

Now, run NeoMutt as normal.

If there are no memory problems, there will be no output from the Address Sanitizer.

Sample Output#

Here’s some sample output from a couple of bugs:

Memory Leak#

This shows a simple memory leak. It shows the callstack up to the point where the memory was allocated.

==61167==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 19 byte(s) in 1 object(s) allocated from:
    #0 0x7eff1fd87667 in __interceptor_malloc (https://neomutt.org/lib64/libasan.so.6+0xb0667)
    #1 0x741c95 in mutt_mem_malloc mutt/memory.c:95
    #2 0x48f089 in get_hostname /home/mutt/work/neo/init.c:343
    #3 0x49259e in mutt_init /home/mutt/work/neo/init.c:929
    #4 0x4a4caa in main /home/mutt/work/neo/main.c:665
    #5 0x7eff1ea1c041 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: 19 byte(s) leaked in 1 allocation(s).

Use After Free#

This use-after-free example shows the callstack in three places:

  • Where the memory was just accessed

  • Where the memory was previously freed

  • Where the memory was originally allocated

==60945==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300004e0d0 at pc 0x7fc99e346f85 bp 0x7ffe360a98f0 sp 0x7ffe360a9098
READ of size 2 at 0x60300004e0d0 thread T0
    #0 0x7fc99e346f84  (https://neomutt.org/lib64/libasan.so.6+0x40f84)
    #1 0x4a9b8e in main /home/mutt/work/neo/main.c:1277
    #2 0x7fc99d04b041 in __libc_start_main ../csu/libc-start.c:308
    #3 0x40d55d in _start (https://neomutt.org/home/mutt/work/neo/neomutt+0x40d55d)

0x60300004e0d0 is located 0 bytes inside of 25-byte region [0x60300004e0d0,0x60300004e0e9)
freed by thread T0 here:
    #0 0x7fc99e3b6307 in __interceptor_free (https://neomutt.org/lib64/libasan.so.6+0xb0307)
    #1 0x741c4f in mutt_mem_free mutt/memory.c:75
    #2 0x49151e in mutt_opts_free /home/mutt/work/neo/init.c:691
    #3 0x4a9b6b in main /home/mutt/work/neo/main.c:1273
    #4 0x7fc99d04b041 in __libc_start_main ../csu/libc-start.c:308

previously allocated by thread T0 here:
    #0 0x7fc99e3603a7 in strdup (https://neomutt.org/lib64/libasan.so.6+0x5a3a7)
    #1 0x74dae5 in mutt_str_dup mutt/string.c:375
    #2 0x74df41 in mutt_str_replace mutt/string.c:451
    #3 0x4a9091 in main /home/mutt/work/neo/main.c:1189
    #4 0x7fc99d04b041 in __libc_start_main ../csu/libc-start.c:308