Changeset View
Changeset View
Standalone View
Standalone View
intern/guardedalloc/intern/leak_detector.cc
| Show All 12 Lines | |||||
| * along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup MEM | * \ingroup MEM | ||||
| */ | */ | ||||
| #include <cstdlib> | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "mallocn_intern.h" | #include "mallocn_intern.h" | ||||
| bool leak_detector_has_run = false; | bool leak_detector_has_run = false; | ||||
| char free_after_leak_detection_message[] = | char free_after_leak_detection_message[] = | ||||
| "Freeing memory after the leak detector has run. This can happen when using " | "Freeing memory after the leak detector has run. This can happen when using " | ||||
| "static variables in C++ that are defined outside of functions. To fix this " | "static variables in C++ that are defined outside of functions. To fix this " | ||||
| "error, use the 'construct on first use' idiom."; | "error, use the 'construct on first use' idiom."; | ||||
| namespace { | namespace { | ||||
| static bool fail_on_memleak = false; | |||||
| class MemLeakPrinter { | class MemLeakPrinter { | ||||
| public: | public: | ||||
| ~MemLeakPrinter() | ~MemLeakPrinter() | ||||
| { | { | ||||
| leak_detector_has_run = true; | leak_detector_has_run = true; | ||||
| const uint leaked_blocks = MEM_get_memory_blocks_in_use(); | const uint leaked_blocks = MEM_get_memory_blocks_in_use(); | ||||
| if (leaked_blocks == 0) { | if (leaked_blocks == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| const size_t mem_in_use = MEM_get_memory_in_use(); | const size_t mem_in_use = MEM_get_memory_in_use(); | ||||
| printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", | printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", | ||||
| leaked_blocks, | leaked_blocks, | ||||
| (double)mem_in_use / 1024 / 1024); | (double)mem_in_use / 1024 / 1024); | ||||
| MEM_printmemlist(); | 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 | } // namespace | ||||
| void MEM_init_memleak_detection(void) | void MEM_init_memleak_detection(void) | ||||
| { | { | ||||
| /** | /** | ||||
| * This variable is constructed when this function is first called. This should happen as soon as | * This variable is constructed when this function is first called. This should happen as soon as | ||||
| * possible when the program starts. | * possible when the program starts. | ||||
| * | * | ||||
| * It is destructed when the program exits. During destruction, it will print information about | * It is destructed when the program exits. During destruction, it will print information about | ||||
| * leaked memory blocks. Static variables are destructed in reversed order of their | * leaked memory blocks. Static variables are destructed in reversed order of their | ||||
| * construction. Therefore, all static variables that own memory have to be constructed after | * construction. Therefore, all static variables that own memory have to be constructed after | ||||
| * this function has been called. | * this function has been called. | ||||
| */ | */ | ||||
| static MemLeakPrinter printer; | static MemLeakPrinter printer; | ||||
| } | } | ||||
| void MEM_enable_fail_on_memleak(void) | |||||
| { | |||||
| fail_on_memleak = true; | |||||
| } | |||||