Address Sanitizer on Mac OS X

Prerequisite

  • LLVM 3.4 with Clang and ASan support
    $ brew tap homebrew/versions
    $ brew install --HEAD llvm34 --with-asan --with-clang --with-libcxx
    

How to use Address Sanitizer (ASan)

$ cat use-after-free.c
#include <stdlib.h>
int main()
{
    char *x = (char*)malloc(10 * sizeof(char*));
  free(x);
  return x[5];
}
  
$ clang-3.4 -g -Os -fno-omit-frame-pointer -fsanitize=address -o use-after-free use-after-free.c
  • -fsanitize=address is to switch ASan on
  • -fno-omit-frame-pointer is to get nicer stack traces in error messages

After you execute it, you'll see something as below:

=================================================================
==19561==ERROR: AddressSanitizer: heap-use-after-free on address 0x60700000cc05 at pc 0x10cef6eb2 bp 0x7fff52d094d0 sp 0x7fff52d094c8
READ of size 1 at 0x60700000cc05 thread T0
    #0 0x10cef6eb1 (/path/to/asan/./use-after-free+0x100000eb1)
    #1 0x7fff88bb77e0 (/usr/lib/system/libdyld.dylib+0x27e0)
    #2 0x0
0x60700000cc05 is located 5 bytes inside of 80-byte region [0x60700000cc00,0x60700000cc50)
freed by thread T0 here:
    #0 0x10cf1720e (/usr/local/lib/llvm-3.4/lib/clang/3.4/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x1b20e)
    #1 0x10cef6e7a (/path/to/asan/./use-after-free+0x100000e7a)
    #2 0x7fff88bb77e0 (/usr/lib/system/libdyld.dylib+0x27e0)
    #3 0x0
previously allocated by thread T0 here:
    #0 0x10cf17140 (/usr/local/lib/llvm-3.4/lib/clang/3.4/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x1b140)
    #1 0x10cef6e6f (/path/to/asan/./use-after-free+0x100000e6f)
    #2 0x7fff88bb77e0 (/usr/lib/system/libdyld.dylib+0x27e0)
    #3 0x0
Shadow bytes around the buggy address:
  0x1c0e00001930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c0e00001980:[fd]fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd
  0x1c0e00001990: fd fd fd fd fd fd fd fd fa fa fa fa 00 00 00 00
  0x1c0e000019a0: 00 00 00 00 00 fa fa fa fa fa 00 00 00 00 00 00
  0x1c0e000019b0: 00 00 00 fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x1c0e000019c0: 00 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 fa
  0x1c0e000019d0: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:     fa
  Heap right redzone:    fb
  Freed heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==19561==ABORTING

You can see much information about the addresses used after free. But I couldn't find actually where are the addresses use-after-free+0x100000eb1 mapping to use-after-free.c. It's easy! Simply specify the ASan symbolizer:

$ ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer-3.4 ./use-after-free
=================================================================
==29587==ERROR: AddressSanitizer: heap-use-after-free on address 0x60700000cc05 at pc 0x10bf79eb2 bp 0x7fff53c86490 sp 0x7fff53c86488
READ of size 1 at 0x60700000cc05 thread T0
    #0 0x10bf79eb1 in main /path/to/asan/use-after-free.c:7
    #1 0x7fff88bb77e0 in start (/usr/lib/system/libdyld.dylib+0x27e0)
    #2 0x0
0x60700000cc05 is located 5 bytes inside of 80-byte region [0x60700000cc00,0x60700000cc50)
freed by thread T0 here:
    #0 0x10bf9c20e in wrap_free (/usr/local/lib/llvm-3.4/lib/clang/3.4/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x1b20e)
    #1 0x10bf79e7a in main /path/to/asan/use-after-free.c:6
    #2 0x7fff88bb77e0 in start (/usr/lib/system/libdyld.dylib+0x27e0)
    #3 0x0
previously allocated by thread T0 here:
    #0 0x10bf9c140 in wrap_malloc (/usr/local/lib/llvm-3.4/lib/clang/3.4/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x1b140)
    #1 0x10bf79e6f in main /path/to/asan/use-after-free.c:5
    #2 0x7fff88bb77e0 in start (/usr/lib/system/libdyld.dylib+0x27e0)
    #3 0x0
SUMMARY: AddressSanitizer: heap-use-after-free /path/to/asan/use-after-free.c:7 main
Shadow bytes around the buggy address:
  0x1c0e00001930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0e00001970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c0e00001980:[fd]fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd
  0x1c0e00001990: fd fd fd fd fd fd fd fd fa fa fa fa 00 00 00 00
  0x1c0e000019a0: 00 00 00 00 00 fa fa fa fa fa 00 00 00 00 00 00
  0x1c0e000019b0: 00 00 00 fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x1c0e000019c0: 00 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 fa
  0x1c0e000019d0: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:     fa
  Heap right redzone:    fb
  Freed heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==29587==ABORTING

Now you know where and how to fix it.