MEM_guarded_alloc: Fix LSAN not reporting memory leaks. #110995
|
@ -41,6 +41,11 @@ class MemLeakPrinter {
|
||||||
double(mem_in_use) / 1024 / 1024);
|
double(mem_in_use) / 1024 / 1024);
|
||||||
MEM_printmemlist();
|
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) {
|
if (fail_on_memleak) {
|
||||||
/* There are many other ways to change the exit code to failure here:
|
/* There are many other ways to change the exit code to failure here:
|
||||||
* - Make the destructor `noexcept(false)` and throw an exception.
|
* - 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;
|
void (*MEM_reset_peak_memory)(void) = MEM_lockfree_reset_peak_memory;
|
||||||
size_t (*MEM_get_peak_memory)(void) = MEM_lockfree_get_peak_memory;
|
size_t (*MEM_get_peak_memory)(void) = MEM_lockfree_get_peak_memory;
|
||||||
|
|
||||||
|
void (*mem_clearmemlist)(void) = mem_lockfree_clearmemlist;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const char *(*MEM_name_ptr)(void *vmemh) = MEM_lockfree_name_ptr;
|
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;
|
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_reset_peak_memory = MEM_lockfree_reset_peak_memory;
|
||||||
MEM_get_peak_memory = MEM_lockfree_get_peak_memory;
|
MEM_get_peak_memory = MEM_lockfree_get_peak_memory;
|
||||||
|
|
||||||
|
mem_clearmemlist = mem_lockfree_clearmemlist;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
MEM_name_ptr = MEM_lockfree_name_ptr;
|
MEM_name_ptr = MEM_lockfree_name_ptr;
|
||||||
MEM_name_ptr_set = MEM_lockfree_name_ptr_set;
|
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_reset_peak_memory = MEM_guarded_reset_peak_memory;
|
||||||
MEM_get_peak_memory = MEM_guarded_get_peak_memory;
|
MEM_get_peak_memory = MEM_guarded_get_peak_memory;
|
||||||
|
|
||||||
|
mem_clearmemlist = mem_guarded_clearmemlist;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
MEM_name_ptr = MEM_guarded_name_ptr;
|
MEM_name_ptr = MEM_guarded_name_ptr;
|
||||||
MEM_name_ptr_set = MEM_guarded_name_ptr_set;
|
MEM_name_ptr_set = MEM_guarded_name_ptr_set;
|
||||||
|
|
|
@ -849,6 +849,10 @@ void MEM_guarded_printmemlist_pydict(void)
|
||||||
{
|
{
|
||||||
MEM_guarded_printmemlist_internal(1);
|
MEM_guarded_printmemlist_internal(1);
|
||||||
}
|
}
|
||||||
|
void mem_guarded_clearmemlist(void)
|
||||||
|
{
|
||||||
|
membase->first = membase->last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void MEM_guarded_freeN(void *vmemh)
|
void MEM_guarded_freeN(void *vmemh)
|
||||||
{
|
{
|
||||||
|
|
|
@ -103,6 +103,16 @@ size_t memory_usage_current(void);
|
||||||
size_t memory_usage_peak(void);
|
size_t memory_usage_peak(void);
|
||||||
void memory_usage_peak_reset(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 */
|
/* Prototypes for counted allocator functions */
|
||||||
size_t MEM_lockfree_allocN_len(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
|
size_t MEM_lockfree_allocN_len(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
|
||||||
void MEM_lockfree_freeN(void *vmemh);
|
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);
|
unsigned int MEM_lockfree_get_memory_blocks_in_use(void);
|
||||||
void MEM_lockfree_reset_peak_memory(void);
|
void MEM_lockfree_reset_peak_memory(void);
|
||||||
size_t MEM_lockfree_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
size_t MEM_lockfree_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
void mem_lockfree_clearmemlist(void);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const char *MEM_lockfree_name_ptr(void *vmemh);
|
const char *MEM_lockfree_name_ptr(void *vmemh);
|
||||||
void MEM_lockfree_name_ptr_set(void *vmemh, const char *str);
|
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);
|
unsigned int MEM_guarded_get_memory_blocks_in_use(void);
|
||||||
void MEM_guarded_reset_peak_memory(void);
|
void MEM_guarded_reset_peak_memory(void);
|
||||||
size_t MEM_guarded_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
size_t MEM_guarded_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
void mem_guarded_clearmemlist(void);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const char *MEM_guarded_name_ptr(void *vmemh);
|
const char *MEM_guarded_name_ptr(void *vmemh);
|
||||||
void MEM_guarded_name_ptr_set(void *vmemh, const char *str);
|
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_printmemlist(void) {}
|
||||||
|
|
||||||
|
void mem_lockfree_clearmemlist(void) {}
|
||||||
|
|
||||||
/* unused */
|
/* unused */
|
||||||
void MEM_lockfree_callbackmemlist(void (*func)(void *))
|
void MEM_lockfree_callbackmemlist(void (*func)(void *))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue