Tools/Debugging/ASAN Address Sanitizer
GCC and Clang support address sanitizer, which will use of uninitialized memory, accessing freed memory, accessing outside memory bounds, and so on. It also supports leak checking when Blender exits.
Enable with the WITH_COMPILER_ASAN option in the CMake configuration. It is also enabled when using make developer to enable development options.
When the output is not enough to go by, run inside a debugger and break on the error reporting function
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
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. For that you can set an environment variable like this, possible in .bashrc or similar to make it permanent.
The contents of blender-lsan-suppressions.txt can be as follows:
leak:_PyObject_Malloc leak:_PyObject_Realloc leak:PyThread_allocate_lock leak:libpython* leak:imb_exitopenexr leak:imb_filetypes_exit leak:libIlm* leak:<unknown module> leak:libX11* leak:libglib* leak:libnvidia* leak:i965_dri leak:libdrm* leak:radeon* leak:libGLX*
Most warnings will come from Python and graphics drivers, the common ones are included here. More can be added as needed, using library and function names, including wildcards.
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:
Comparison with Valgrind
Address sanitizer can help find bugs that Valgrind would, but there are some important differences.
- 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).
- 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)
This feature is quite in-depth and this doc only explains basic usage, for further reading: