Tools/Debugging/GCC Address Sanitizer

From Blender Developer Wiki
Jump to: navigation, search

ASAN

GCC 4.8 adds address sanitizer, this will cause blender to quit with an error message on bad memory use (using uninitialized memory, accessing freed memory, accessing outside memory bounds).

Also, since GCC 4.9, ASAN adds a memory leak checking (LeakSanitizer) that reports when closing Blender.

Usage

Enable the address sanitize flag,

-fsanitize=address
  • CMake: add to 'CMAKE_CXX_FLAGS_DEBUG' and 'CMAKE_C_FLAGS_DEBUG'.
  • SCons: add to 'BF_DEBUG_CCFLAGS'

Then run blender until it crashes with an address sanitizer style error.

The output of asan is rather cryptic (raw address offsets). To get human-readable backtraces, you can use the asan_symbolize.py python2 script, which is part of the llvm project:

./bin/blender 2>&1 | asan_symbolize.py

If you are working with C++ code, you may want to add the -d option to asan_symbolize.py call, to demangle names.

When the output is not enough to go by, run inside a debugger and break on the error reporting function

break __asan_report_error

Example stack trace:

#0  0x00007ffff4e63e40 in __asan_report_error () from /usr/lib/libasan.so.0
#1  0x00007ffff4e5e804 in __asan_report_load1 () from /usr/lib/libasan.so.0
#2  0x0000000002450a77 in mywrite (wd=0x600c0028cd60, adr=0x602c00048340, len=376) at ./source/blender/blenloader/intern/writefile.c:297
#3  0x0000000002451413 in writedata (wd=0x600c0028cd60, filecode=1096040772, len=376, adr=0x602c00048340) at ./source/blender/blenloader/intern/writefile.c:395
#4  0x0000000002462edc in write_texts (wd=0x600c0028cd60, idbase=0x60500000f5c8) at ./source/blender/blenloader/intern/writefile.c:2679
#5  0x0000000002466826 in write_file_handle (mainvar=0x60500000f080, handle=0, compare=0x6044000158d0, current=0x60440004a5d0, write_user_block=0, write_flags=4608, thumb=0x0) at ./source/blender/blenloader/intern/writefile.c:3284
#6  0x0000000002467631 in BLO_write_file_mem (mainvar=0x60500000f080, compare=0x6044000158d0, current=0x60440004a5d0, write_flags=4608) at ./source/blender/blenloader/intern/writefile.c:3485
#7  0x0000000001e0105b in BKE_write_undo (C=0x60160000af90, name=0x3007820 "Open Text Block") at ./source/blender/blenkernel/intern/blender.c:676
#8  0x0000000000d34ee6 in ED_undo_push (C=0x60160000af90, str=0x3007820 "Open Text Block") at ./source/blender/editors/util/undo.c:110
#9  0x0000000000d356ba in ED_undo_push_op (C=0x60160000af90, op=0x601e00005b30) at ./source/blender/editors/util/undo.c:220
#10 0x000000000088ec97 in wm_handler_fileselect_call (C=0x60160000af90, handlers=0x60240007cd50, handler=0x601a0004b390, event=0x6018001cf180) at ./source/blender/windowmanager/intern/wm_event_system.c:1622
#11 0x000000000088fc90 in wm_handlers_do_intern (C=0x60160000af90, event=0x6018001cf180, handlers=0x60240007cd50) at ./source/blender/windowmanager/intern/wm_event_system.c:1816
#12 0x0000000000890237 in wm_handlers_do (C=0x60160000af90, event=0x6018001cf180, handlers=0x60240007cd50) at ./source/blender/windowmanager/intern/wm_event_system.c:1891
#13 0x00000000008919bc in wm_event_do_handlers (C=0x60160000af90) at ./source/blender/windowmanager/intern/wm_event_system.c:2138
#14 0x00000000008781dd in WM_main (C=0x60160000af90) at ./source/blender/windowmanager/intern/wm.c:447
#15 0x000000000087648a in main (argc=1, argv=0x7fffffffe058) at ./source/creator/creator.c:1646

Quiet LeakSanitizer

While this tool is really useful to detect memory leaks, it has some annoying drawback in Blender currently - usage of Python leads to a fair amount of (valid!) leak reports, about which we cannot do much currently (see also Python documentation).

To silence those warnings (which can “hide” a real new one in the flow), you can use a suppression file and pass it as environment variable to run Blender:

$ LSAN_OPTIONS=suppressions=path/to/asan_blender_sup.txt path/to/bin/blender

asan_blender_sup.txt can contain several suppression rules (libraries or function names, including wildcards), but that single one should already remove most reports:

leak:libpython*

Please note that this will remove any leak reports from code which backtrace contains a reference to libpython - this may be too generic, in which case just filtering out leaks coming from our bpy init code can be an option:

leak:BPY_python_start

Note that you can also add some rule for your GPU driver, those also tend to not free all their memory upon termination…

eg (for intel cards):

leak:libdrm_intel
leak:i965_dri

Comparison with Valgrind

Address sanitizer can help find bugs that Valgrind would, but there are some important differences.

Pros

  • Fast enough for general use.
  • Easy to use a breakpoint to investigate the point when and error happens.
    (Valgrind can use GDB too but its a bit more involved).

Cons

  • Only deals with heap memory (not stack as valgrind).
  • Can't be used with valgrind
    (to use valgrind you'll have to remove the compiler flags and rebuild)

Further Reading

This feature is quite in-depth and this doc only explains basic usage, for further reading: