diff options
author | Jacques Lucke <jacques@blender.org> | 2020-08-21 12:35:51 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2020-08-21 12:49:57 +0300 |
commit | 3b93022e9213fce8b378bbc4d6ba229c2ddc849f (patch) | |
tree | e5aa9f544e84f1eb180c36d1208d36a8105cb16d | |
parent | 41d31e100d9d76aa8f20bd9fe8429122828dc7a9 (diff) |
Tests: detect memory leaks in automated testsfail-on-memleak
A memory leak should be considered a bug. Therefore, it makes sense to fail tests when they contain memory leaks.
Differential Revision: https://developer.blender.org/D8665
-rw-r--r-- | intern/guardedalloc/MEM_guardedalloc.h | 5 | ||||
-rw-r--r-- | intern/guardedalloc/intern/leak_detector.cc | 19 | ||||
-rw-r--r-- | source/creator/creator_args.c | 14 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/gtests/testing/testing_main.cc | 1 | ||||
-rw-r--r-- | tests/python/collada/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/python/cycles_render_tests.py | 2 | ||||
-rw-r--r-- | tests/python/eevee_render_tests.py | 2 | ||||
-rwxr-xr-x | tests/python/modules/test_utils.py | 2 | ||||
-rw-r--r-- | tests/python/opengl_draw_tests.py | 2 | ||||
-rw-r--r-- | tests/python/view_layer/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/python/workbench_render_tests.py | 2 |
12 files changed, 54 insertions, 5 deletions
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 9c62b2396f6..c05bda030ad 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -215,6 +215,11 @@ extern const char *(*MEM_name_ptr)(void *vmemh); * about memory leaks will be printed on exit. */ void MEM_init_memleak_detection(void); +/** When this has been called and memory leaks have been detected, the process will have an exit + * code that indicates failure. This can be used for when checking for memory leaks with automated + * tests. */ +void MEM_enable_fail_on_memleak(void); + /* Switch allocator to slower but fully guarded mode. */ void MEM_use_guarded_allocator(void); diff --git a/intern/guardedalloc/intern/leak_detector.cc b/intern/guardedalloc/intern/leak_detector.cc index d7b6f749742..bb816e7f2d3 100644 --- a/intern/guardedalloc/intern/leak_detector.cc +++ b/intern/guardedalloc/intern/leak_detector.cc @@ -18,6 +18,8 @@ * \ingroup MEM */ +#include <cstdlib> + #include "MEM_guardedalloc.h" #include "mallocn_intern.h" @@ -28,6 +30,9 @@ char free_after_leak_detection_message[] = "error, use the 'construct on first use' idiom."; namespace { + +static bool fail_on_memleak = false; + class MemLeakPrinter { public: ~MemLeakPrinter() @@ -42,6 +47,15 @@ class MemLeakPrinter { leaked_blocks, (double)mem_in_use / 1024 / 1024); MEM_printmemlist(); + + if (fail_on_memleak) { + /* There are many other ways to change the exit code to failure here: + * - Make the destructor noexcept(false) and throw an exception. + * - Call exit(EXIT_FAILURE). + * - Call terminate(). + */ + abort(); + } } }; } // namespace @@ -59,3 +73,8 @@ void MEM_init_memleak_detection(void) */ static MemLeakPrinter printer; } + +void MEM_enable_fail_on_memleak(void) +{ + fail_on_memleak = true; +} diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 164e670c444..cef1e75e04d 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -751,6 +751,18 @@ static int arg_handle_abort_handler_disable(int UNUSED(argc), return 0; } +static const char arg_handle_fail_on_memleak_doc[] = + "\n\t" + "Exit with an exit code that indicates failure when memory leaks are detected.\n" + "This can be used to make automated tests fail."; +static int arg_handle_fail_on_memleak(int UNUSED(argc), + const char **UNUSED(argv), + void *UNUSED(data)) +{ + MEM_enable_fail_on_memleak(); + return 0; +} + static const char arg_handle_background_mode_set_doc[] = "\n\t" "Run in background (often used for UI-less rendering)."; @@ -2267,6 +2279,8 @@ void main_args_setup(bContext *C, bArgs *ba) BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL); BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C); + BLI_argsAdd(ba, 1, NULL, "--fail-on-memleak", CB(arg_handle_fail_on_memleak), NULL); + # undef CB # undef CB_EX } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0ee3b500fdf..73e318943d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,7 +44,7 @@ unset(_default_test_python_exe) # Standard Blender arguments for running tests. # Specify exit code so that if a Python script error happens, the test fails. -set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --python-exit-code 1) +set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --fail-on-memleak --python-exit-code 1) # Python CTests if(WITH_BLENDER AND WITH_PYTHON) diff --git a/tests/gtests/testing/testing_main.cc b/tests/gtests/testing/testing_main.cc index e9313b31909..6238101b319 100644 --- a/tests/gtests/testing/testing_main.cc +++ b/tests/gtests/testing/testing_main.cc @@ -50,6 +50,7 @@ int main(int argc, char **argv) { MEM_use_guarded_allocator(); MEM_init_memleak_detection(); + MEM_enable_fail_on_memleak(); testing::InitGoogleTest(&argc, argv); BLENDER_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); diff --git a/tests/python/collada/CMakeLists.txt b/tests/python/collada/CMakeLists.txt index bf22de6b762..918599033a8 100644 --- a/tests/python/collada/CMakeLists.txt +++ b/tests/python/collada/CMakeLists.txt @@ -36,12 +36,12 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR}) # all calls to blender use this if(APPLE) if(${CMAKE_GENERATOR} MATCHES "Xcode") - set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --fail-on-memleak) else() - set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --fail-on-memleak --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) endif() else() - set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) + set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --fail-on-memleak --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) endif() # for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index bdf4283eb3e..60453bc350e 100644 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -20,6 +20,8 @@ def get_arguments(filepath, output_filepath): "-noaudio", "--factory-startup", "--enable-autoexec", + "--debug-memory", + "--fail-on-memleak", filepath, "-E", "CYCLES", "-o", output_filepath, diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py index a7130136d0a..290768922be 100644 --- a/tests/python/eevee_render_tests.py +++ b/tests/python/eevee_render_tests.py @@ -103,6 +103,8 @@ def get_arguments(filepath, output_filepath): "-noaudio", "--factory-startup", "--enable-autoexec", + "--debug-memory", + "--fail-on-memleak", filepath, "-E", "BLENDER_EEVEE", "-P", diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py index e31db05ba61..77fcdd184e3 100755 --- a/tests/python/modules/test_utils.py +++ b/tests/python/modules/test_utils.py @@ -79,6 +79,8 @@ class AbstractBlenderRunnerTest(unittest.TestCase): '-noaudio', '--factory-startup', '--enable-autoexec', + '--debug-memory', + '--fail-on-memleak', ] if blendfile: diff --git a/tests/python/opengl_draw_tests.py b/tests/python/opengl_draw_tests.py index ab4df63afd9..36cce29c92c 100644 --- a/tests/python/opengl_draw_tests.py +++ b/tests/python/opengl_draw_tests.py @@ -39,6 +39,8 @@ def get_arguments(filepath, output_filepath): "-noaudio", "--factory-startup", "--enable-autoexec", + "--debug-memory", + "--fail-on-memleak", filepath, "-P", os.path.realpath(__file__), diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index 3f38ee4675f..efcb15ba172 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -30,7 +30,7 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR}) # endif() # for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no -set(TEST_BLENDER_EXE $<TARGET_FILE:blender> --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) +set(TEST_BLENDER_EXE $<TARGET_FILE:blender> --background -noaudio --factory-startup --debug-memory --fail-on-memleak --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) # ------------------------------------------------------------------------------ diff --git a/tests/python/workbench_render_tests.py b/tests/python/workbench_render_tests.py index 155b54098a8..f1ea55165f4 100644 --- a/tests/python/workbench_render_tests.py +++ b/tests/python/workbench_render_tests.py @@ -39,6 +39,8 @@ def get_arguments(filepath, output_filepath): "-noaudio", "--factory-startup", "--enable-autoexec", + "--debug-memory", + "--fail-on-memleak", filepath, "-E", "BLENDER_WORKBENCH", "-P", |