-
Notifications
You must be signed in to change notification settings - Fork 0
/
MEM_debug.h
141 lines (110 loc) · 7.59 KB
/
MEM_debug.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
MEM_debug, a heap corruption and memory leak detector.
Copyright (c)2021 Itay Chamiel, [email protected]
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product or in the course of product development, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef MEM_DEBUG_H_
#define MEM_DEBUG_H_
#include <stddef.h>
#include <stdint.h>
// Comment this line out to completely disable the memory checker.
#define MEM_DEBUG_ENABLE
#ifdef __cplusplus
/* C++ interface */
namespace mem_debug {
#ifdef MEM_DEBUG_ENABLE
// Checks integrity of all allocated memory and displays results. It is best not to use this function directly but use one of the below macros.
void mem_debug_check(const char* file, const int line, const char* user_msg = NULL, const bool this_thread_only = false);
// Performs integrity check and displays amount and size of all memory allocation.
#define MEM_DEBUG_CHECK mem_debug::mem_debug_check(__FILE__, __LINE__);
// Same as MEM_DEBUG_CHECK but allows a custom message to be shown along with results.
#define MEM_DEBUG_CHECK_MSG(msg) mem_debug::mem_debug_check(__FILE__, __LINE__, msg);
// Same as MEM_DEBUG_CHECK_MSG but displays results for memory allocated by the calling thread only.
#define MEM_DEBUG_THREAD_CHECK(msg) mem_debug::mem_debug_check(__FILE__, __LINE__, msg, true);
// Integrity check on a single pointer; this will only work on a pointer that can be unallocated using 'free'. (that is, obtained by a previous
// use of malloc or similar call and not modified). It has also been tested on pointers obtained via 'new' but this is may fail on certain platforms.
void check_ptr(const void* ptr);
// Clear records of allocated memory, to prepare for a leak test.
// is_global defines scope of operation, true for process-wide, false for current thread's allocations only.
// restart_serial_nums also resets all (process/thread) allocations' serial numbers, and restarts assignment from 0.
void clear_leak_list(bool is_global = false, bool restart_serial_nums = false);
// Display all memory buffers allocated since the last clear_leak_list (or program start).
// is_global=true to display all process's allocs, false to display current thread's only.
// returns false if no leaks detected, true if leaks detected.
bool show_leak_list(bool is_global = false);
// Cause mem_debug to abort the program on a specific allocation (defined by serial number), optionally only if equal to a specific size, global or in current thread.
void abort_on_allocation(unsigned int serial_num, unsigned int size = 0, bool is_global = false);
// Returns total amount of bytes currently allocated by program (with or without extra padding allocated by mem_debug).
// Setting get_peak to true will return the respective current peak value.
// Setting is_global to false will return information pertaining to current thread only.
uint64_t get_total_alloced_bytes(bool include_padding = false, bool get_peak = false, bool is_global = true);
// Returns total amount of allocated blocks.
// Setting is_global to false will return information pertaining to current thread only.
// outstanding_only = false: returns the number of times malloc was called. true: returns number of currently allocated blocks.
uint64_t get_total_mallocs(bool is_global = true, bool outstanding_only = true);
// Set an upper bound on memory usage. Any attempt to allocate memory such that the total heap usage grows beyond max_usage will fail.
// This does not count the padding and bookkeeping used by MEM_debug itself. Set to 0 to disable.
void set_memory_limit(uint64_t max_usage);
// Finds thread which has allocated the highest proportion of currently allocated memory and returns its TID and the amount of memory it has allocated.
void get_largest_thread(int* tid, uint64_t* alloc_size);
#else
static inline void mem_debug_check(const char* file, const int line, const char* user_msg = NULL, const bool this_thread_only = false) {}
static inline void check_ptr(const void* ptr) {}
static inline void clear_leak_list(bool is_global = false, bool restart_serial_nums = false) {}
static inline bool show_leak_list(bool is_global = false) { return false; }
static inline void abort_on_allocation(unsigned int serial_num, unsigned int size = -1, bool is_global = false) {}
static inline uint64_t get_total_alloced_bytes(bool include_padding = false, bool get_peak = false, bool is_global = true) { return 0; }
static inline uint64_t get_total_mallocs(bool is_global = true, bool outstanding_only = true) { return 0; }
static inline void set_memory_limit(uint64_t max_usage) {}
static inline void get_largest_thread(int* tid, uint64_t* alloc_size) {}
#define MEM_DEBUG_CHECK
#define MEM_DEBUG_CHECK_MSG(msg)
#define MEM_DEBUG_THREAD_CHECK(msg)
#endif
} // namespace
#else // __cplusplus not defined
// C language interface. Functionality is the same as above but substitute integer constants MD_TRUE and MD_FALSE for true/false boolean values.
// Function names are all prefixed with "mem_debug" since there's no namespace.
#define MD_TRUE 1
#define MD_FALSE 0
#ifdef MEM_DEBUG_ENABLE
void mem_debug_check(const char* file, const int line, const char* user_msg, const int bool_this_thread_only);
#define MEM_DEBUG_CHECK mem_debug_check(__FILE__, __LINE__, NULL, MD_FALSE);
#define MEM_DEBUG_CHECK_MSG(msg) mem_debug_check(__FILE__, __LINE__, msg, MD_FALSE);
#define MEM_DEBUG_THREAD_CHECK(msg) mem_debug_check(__FILE__, __LINE__, msg, MD_TRUE);
void mem_debug_check_ptr(const void* ptr);
void mem_debug_clear_leak_list(int bool_is_global, int bool_restart_serial_nums);
int mem_debug_show_leak_list(int bool_is_global);
void mem_debug_abort_on_allocation(unsigned int serial_num, unsigned int size, int bool_is_global);
uint64_t mem_debug_get_total_alloced_bytes(int bool_include_padding, int get_peak, int is_global);
uint64_t mem_debug_get_total_mallocs(int is_global, int outstanding_only);
void mem_debug_set_memory_limit(uint64_t max_usage);
void mem_debug_get_largest_thread(int* tid, uint64_t* alloc_size);
#else
static inline void mem_debug_check(const char* file, const int line, const char* user_msg, const int bool_this_thread_only) {}
static inline void mem_debug_check_ptr(const void* ptr) {}
static inline void mem_debug_clear_leak_list(int bool_is_global, int bool_restart_serial_nums) {}
static inline int mem_debug_show_leak_list(int bool_is_global) { return MD_FALSE; }
static inline void mem_debug_abort_on_allocation(unsigned int serial_num, unsigned int size, int bool_is_global) {}
static inline uint64_t mem_debug_get_total_alloced_bytes(int bool_include_padding, int get_peak, int is_global) { return 0; }
static inline uint64_t mem_debug_get_total_mallocs(int is_global, int outstanding_only) { return 0; }
static inline void mem_debug_set_memory_limit(uint64_t max_usage) {}
static inline void mem_debug_get_largest_thread(int* tid, uint64_t* alloc_size) {}
#define MEM_DEBUG_CHECK
#define MEM_DEBUG_CHECK_MSG(msg)
#define MEM_DEBUG_THREAD_CHECK(msg)
#endif
#endif // __cplusplus
#endif /* MEM_DEBUG_H_ */