MEM_guarded_alloc: Fix LSAN not reporting memory leaks. #110995
|
@ -41,6 +41,11 @@ class MemLeakPrinter {
|
|||
double(mem_in_use) / 1024 / 1024);
|
||||
MEM_printmemlist();
|
||||
|
||||
/* In guarded implementation, the fact that all allocated memory blocks are stored in the
|
||||
* static `membase` listbase is enough for LSAN to not detect them as leaks. Clearing it solves
|
||||
* that issue. */
|
||||
mem_clearmemlist();
|
||||
|
||||
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.
|
||||
|
|
|
@ -49,6 +49,8 @@ uint (*MEM_get_memory_blocks_in_use)(void) = MEM_lockfree_get_memory_blocks_in_u
|
|||
void (*MEM_reset_peak_memory)(void) = MEM_lockfree_reset_peak_memory;
|
||||
size_t (*MEM_get_peak_memory)(void) = MEM_lockfree_get_peak_memory;
|
||||
|
||||
void (*mem_clearmemlist)(void) = mem_lockfree_clearmemlist;
|
||||
|
||||
#ifndef NDEBUG
|
||||
const char *(*MEM_name_ptr)(void *vmemh) = MEM_lockfree_name_ptr;
|
||||
void (*MEM_name_ptr_set)(void *vmemh, const char *str) = MEM_lockfree_name_ptr_set;
|
||||
|
@ -129,6 +131,8 @@ void MEM_use_lockfree_allocator(void)
|
|||
MEM_reset_peak_memory = MEM_lockfree_reset_peak_memory;
|
||||
MEM_get_peak_memory = MEM_lockfree_get_peak_memory;
|
||||
|
||||
mem_clearmemlist = mem_lockfree_clearmemlist;
|
||||
|
||||
#ifndef NDEBUG
|
||||
MEM_name_ptr = MEM_lockfree_name_ptr;
|
||||
MEM_name_ptr_set = MEM_lockfree_name_ptr_set;
|
||||
|
@ -161,6 +165,8 @@ void MEM_use_guarded_allocator(void)
|
|||
MEM_reset_peak_memory = MEM_guarded_reset_peak_memory;
|
||||
MEM_get_peak_memory = MEM_guarded_get_peak_memory;
|
||||
|
||||
mem_clearmemlist = mem_guarded_clearmemlist;
|
||||
|
||||
#ifndef NDEBUG
|
||||
MEM_name_ptr = MEM_guarded_name_ptr;
|
||||
MEM_name_ptr_set = MEM_guarded_name_ptr_set;
|
||||
|
|
|
@ -849,6 +849,10 @@ void MEM_guarded_printmemlist_pydict(void)
|
|||
{
|
||||
MEM_guarded_printmemlist_internal(1);
|
||||
}
|
||||
void mem_guarded_clearmemlist(void)
|
||||
{
|
||||
membase->first = membase->last = NULL;
|
||||
}
|
||||
|
||||
void MEM_guarded_freeN(void *vmemh)
|
||||
{
|
||||
|
|
|
@ -103,6 +103,16 @@ size_t memory_usage_current(void);
|
|||
size_t memory_usage_peak(void);
|
||||
void memory_usage_peak_reset(void);
|
||||
|
||||
/**
|
||||
* Clear the listbase of allocated memory blocks.
|
||||
*
|
||||
* WARNING: This will make the whole guardedalloc system fully inconsistent. It is only intented to
|
||||
* be called in one place: the destructor of the #MemLeakPrinter class, which is only
|
||||
* instantiated once as a static variable by #MEM_init_memleak_detection, and therefore destructed
|
||||
* once at program exit.
|
||||
*/
|
||||
extern void (*mem_clearmemlist)(void);
|
||||
|
||||
/* Prototypes for counted allocator functions */
|
||||
size_t MEM_lockfree_allocN_len(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
|
||||
void MEM_lockfree_freeN(void *vmemh);
|
||||
|
@ -142,6 +152,9 @@ size_t MEM_lockfree_get_memory_in_use(void);
|
|||
unsigned int MEM_lockfree_get_memory_blocks_in_use(void);
|
||||
void MEM_lockfree_reset_peak_memory(void);
|
||||
size_t MEM_lockfree_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
void mem_lockfree_clearmemlist(void);
|
||||
|
||||
#ifndef NDEBUG
|
||||
const char *MEM_lockfree_name_ptr(void *vmemh);
|
||||
void MEM_lockfree_name_ptr_set(void *vmemh, const char *str);
|
||||
|
@ -186,6 +199,9 @@ size_t MEM_guarded_get_memory_in_use(void);
|
|||
unsigned int MEM_guarded_get_memory_blocks_in_use(void);
|
||||
void MEM_guarded_reset_peak_memory(void);
|
||||
size_t MEM_guarded_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
void mem_guarded_clearmemlist(void);
|
||||
|
||||
#ifndef NDEBUG
|
||||
const char *MEM_guarded_name_ptr(void *vmemh);
|
||||
void MEM_guarded_name_ptr_set(void *vmemh, const char *str);
|
||||
|
|
|
@ -338,6 +338,8 @@ void MEM_lockfree_printmemlist_pydict(void) {}
|
|||
|
||||
void MEM_lockfree_printmemlist(void) {}
|
||||
|
||||
void mem_lockfree_clearmemlist(void) {}
|
||||
|
||||
/* unused */
|
||||
void MEM_lockfree_callbackmemlist(void (*func)(void *))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue