24#ifdef WITH_MEM_VALGRIND
25# include "valgrind/memcheck.h"
29#include "../../source/blender/blenlib/BLI_strict_flags.h"
60# define DEBUG_BACKTRACE
74# if defined(__linux__) || defined(__APPLE__)
75# define DEBUG_BACKTRACE_EXECINFO
77# error "DEBUG_BACKTRACE: not supported for this platform!"
82#ifdef DEBUG_BACKTRACE_EXECINFO
83# define BACKTRACE_SIZE 100
86#ifdef DEBUG_MEMCOUNTER
88# define DEBUG_MEMCOUNTER_ERROR_VAL 0
89static int _mallocn_count = 0;
92static void memcount_raise(
const char *name)
94 fprintf(stderr,
"%s: memcount-leak, %d\n", name, _mallocn_count);
121#ifdef DEBUG_MEMCOUNTER
125#ifdef DEBUG_MEMDUPLINAME
126 int need_free_name,
pad;
129#ifdef DEBUG_BACKTRACE_EXECINFO
130 void *backtrace[BACKTRACE_SIZE];
135static_assert(MEM_MIN_CPP_ALIGNMENT <=
alignof(
MemHead),
"Bad alignment of MemHead");
136static_assert(MEM_MIN_CPP_ALIGNMENT <=
sizeof(
MemHead),
"Bad size of MemHead");
155#ifdef DEBUG_BACKTRACE_EXECINFO
156# include <execinfo.h>
174# define MAKE_ID(a, b, c, d) (int(a) << 24 | int(b) << 16 | (c) << 8 | (d))
176# define MAKE_ID(a, b, c, d) (int(d) << 24 | int(c) << 16 | (b) << 8 | (a))
179#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
180#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
181#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
182#define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
184#define MEMNEXT(x) ((MemHead *)(((char *)x) - offsetof(MemHead, next)))
222 vsnprintf(buf,
sizeof(buf), message, str_format_args);
223 buf[
sizeof(buf) - 1] =
'\0';
239 va_list str_format_args;
240 va_start(str_format_args, message);
242 va_end(str_format_args);
251 va_list str_format_args;
253 va_start(str_format_args, message);
255 va_end(str_format_args);
257 if (vmemh ==
nullptr) {
266 const void *address = memh;
267 size_t size =
len +
sizeof(*memh) +
sizeof(
MemTail);
291 const char *err_val =
nullptr;
299 return (err_val ==
nullptr);
326 void *newp =
nullptr;
334 "Attempt to use C-style MEM_dupallocN on a pointer created with "
335 "CPP-style MEM_new or new\n");
338#ifndef DEBUG_MEMDUPLINAME
344 memh->
len,
size_t(memh->
alignment),
"dupli_alloc", AllocationType::ALLOC_FREE);
347 if (newp ==
nullptr) {
353 const char name_prefix[] =
"dupli_alloc ";
354 const size_t name_prefix_len =
sizeof(name_prefix) - 1;
355 const size_t name_size = strlen(memh->
name) + 1;
356 char *name = malloc(name_prefix_len + name_size);
357 memcpy(name, name_prefix,
sizeof(name_prefix));
358 memcpy(name + name_prefix_len, memh->
name, name_size);
365 memh->
len, (
size_t)memh->
alignment, name, AllocationType::ALLOC_FREE);
374 nmemh->need_free_name = 1;
378 memcpy(newp, vmemh, memh->
len);
386 void *newp =
nullptr;
394 "Attempt to use C-style MEM_reallocN on a pointer created with "
395 "CPP-style MEM_new or new\n");
409 memcpy(newp, vmemh,
len);
413 memcpy(newp, vmemh, memh->
len);
428 void *newp =
nullptr;
436 "Attempt to use C-style MEM_recallocN on a pointer created with "
437 "CPP-style MEM_new or new\n");
451 memcpy(newp, vmemh,
len);
454 memcpy(newp, vmemh, memh->
len);
459 memset(((
char *)newp) + memh->
len, 0,
len - memh->
len);
473#ifdef DEBUG_BACKTRACE_EXECINFO
474static void make_memhead_backtrace(
MemHead *memh)
476 memh->backtrace_size = backtrace(memh->backtrace, BACKTRACE_SIZE);
479static void print_memhead_backtrace(
MemHead *memh)
484 strings = backtrace_symbols(memh->backtrace, memh->backtrace_size);
485 for (i = 0; i < memh->backtrace_size; i++) {
508#ifdef DEBUG_MEMDUPLINAME
509 memh->need_free_name = 0;
512#ifdef DEBUG_BACKTRACE_EXECINFO
513 make_memhead_backtrace(memh);
535#ifdef WITH_MEM_VALGRIND
536 const size_t len_unaligned =
len;
547 memset(memh + 1, 255,
len);
549#ifdef WITH_MEM_VALGRIND
551 VALGRIND_MAKE_MEM_UNDEFINED(memh + 1, len_unaligned);
554 VALGRIND_MAKE_MEM_DEFINED((
const char *)(memh + 1) + len_unaligned,
len - len_unaligned);
559#ifdef DEBUG_MEMCOUNTER
560 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
561 memcount_raise(__func__);
562 memh->_count = _mallocn_count++;
578 "Malloc array aborted due to integer overflow: "
598 assert(alignment < 1024);
618#ifdef WITH_MEM_VALGRIND
619 const size_t len_unaligned =
len;
631 memh = (
MemHead *)((
char *)memh + extra_padding);
637 memset(memh + 1, 255,
len);
639#ifdef WITH_MEM_VALGRIND
641 VALGRIND_MAKE_MEM_UNDEFINED(memh + 1, len_unaligned);
644 VALGRIND_MAKE_MEM_DEFINED((
const char *)(memh + 1) + len_unaligned,
len - len_unaligned);
649#ifdef DEBUG_MEMCOUNTER
650 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
651 memcount_raise(__func__);
652 memh->_count = _mallocn_count++;
673#ifdef DEBUG_MEMCOUNTER
674 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
675 memcount_raise(__func__);
676 memh->_count = _mallocn_count++;
692 "Calloc array aborted due to integer overflow: "
707 const size_t alignment,
713 "Calloc array aborted due to integer overflow: "
722 if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
731 memset(
ptr, 0, bytes_num);
747 return strcmp(pb1->
name, pb2->
name);
755 if (pb1->
len < pb2->
len) {
758 if (pb1->
len == pb2->
len) {
770 size_t mem_in_use_slop = 0;
780 print_error(
"malloc returned null while generating stats");
785 printblock =
nullptr;
796 while (membl && pb) {
804#ifdef USE_MALLOC_USABLE_SIZE
806 mem_in_use_slop += (
sizeof(
MemHead) +
sizeof(
MemTail) + malloc_usable_size((
void *)membl)) -
824 for (a = 0,
b = 0; a < totpb; a++) {
828 if (strcmp(printblock[a].name, printblock[
b].name) == 0) {
829 printblock[
b].
len += printblock[a].
len;
844 printf(
"\ntotal memory len: %.3f MB\n",
double(
mem_in_use) /
double(1024 * 1024));
845 printf(
"peak memory len: %.3f MB\n",
double(
peak_mem) /
double(1024 * 1024));
846 printf(
"slop memory len: %.3f MB\n",
double(mem_in_use_slop) /
double(1024 * 1024));
847 printf(
" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
848 for (a = 0, pb = printblock; a < totpb; a++, pb++) {
849 printf(
"%6d (%8.3f %8.3f) %s\n",
851 double(pb->
len) /
double(1024 * 1024),
852 double(pb->
len) / 1024.0 /
double(pb->
items),
856 if (printblock !=
nullptr) {
862#ifdef HAVE_MALLOC_STATS
863 printf(
"System Statistics:\n");
871 "for mb_item in membase:\n"
872 " mb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
873 " mb_item_user_size[0] += 1 # Add a user\n"
874 " mb_item_user_size[1] += mb_item['len'] # Increment the size\n"
875 " totmem += mb_item['len']\n"
876 "print('(membase) items:', len(membase), '| unique-names:',\n"
877 " len(mb_userinfo), '| total-mem:', totmem)\n"
878 "mb_userinfo_sort = list(mb_userinfo.items())\n"
879 "for sort_name, sort_func in (('size', lambda a: -a[1][1]),\n"
880 " ('users', lambda a: -a[1][0]),\n"
881 " ('name', lambda a: a[0])):\n"
882 " print('\\nSorting by:', sort_name)\n"
883 " mb_userinfo_sort.sort(key = sort_func)\n"
884 " for item in mb_userinfo_sort:\n"
885 " print('name:%%s, users:%%i, len:%%i' %%\n"
886 " (item[0], item[1][0], item[1][1]))\n";
909 "'pointer':'%p'},\n",
912 (
void *)(membl + 1));
915#ifdef DEBUG_MEMCOUNTER
925 (
void *)(membl + 1));
928#ifdef DEBUG_BACKTRACE_EXECINFO
929 print_memhead_backtrace(membl);
930#elif defined(DEBUG_BACKTRACE) && defined(WITH_ASAN)
931 __asan_describe_address(membl);
974short MEM_guarded_testN(
void *vmemh)
985 if (vmemh == membl + 1) {
998 print_error(
"Memoryblock %p: pointer not in memlist\n", vmemh);
1022 if (memh ==
nullptr) {
1023 MemorY_ErroR(
"free",
"attempt to free nullptr pointer");
1030 MemorY_ErroR(
"free",
"attempt to free illegal pointer");
1036 MemorY_ErroR(
"free",
"attempt to free illegal pointer");
1043 if (allocation_type != AllocationType::NEW_DELETE &&
1048 "Attempt to use C-style MEM_freeN on a pointer created with CPP-style MEM_new or new\n");
1057 memt = (
MemTail *)(((
char *)memh) +
sizeof(
MemHead) + memh->len);
1074 if (name !=
nullptr) {
1075 if (name != memh->name) {
1084 if (name ==
nullptr) {
1107 if (link ==
nullptr)
1109 if (listbase ==
nullptr)
1113 link->
next =
nullptr;
1116 if (listbase->
last) {
1119 if (listbase->
first ==
nullptr) {
1120 listbase->
first = link;
1122 listbase->
last = link;
1132 if (link ==
nullptr)
1134 if (listbase ==
nullptr)
1145 if (listbase->
last == link) {
1148 if (listbase->
first == link) {
1170#ifdef DEBUG_MEMDUPLINAME
1171 if (memh->need_free_name)
1176 memset(memh + 1, 255, memh->
len);
1190#ifdef WITH_ASSERT_ABORT
1197 MemHead *forw, *back, *forwok, *backok;
1237 return (
"MORE THAN 1 MEMORYBLOCK CORRUPT");
1240 if (forw ==
nullptr && back ==
nullptr) {
1263 if (forw ==
nullptr) {
1293 name =
"No name found";
1305 forwok->
next =
nullptr;
1311 backok->
prev =
nullptr;
1321 return (
"Additional error in header");
1376 return "MEM_guarded_name_ptr(nullptr)";
void BLI_kdtree_nd_ free(KDTree *tree)
Read Guarded memory(de)allocation.
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE unsigned int atomic_add_and_fetch_u(unsigned int *p, unsigned int x)
ATOMIC_INLINE unsigned int atomic_sub_and_fetch_u(unsigned int *p, unsigned int x)
int pad[32 - sizeof(int)]
local_group_size(16, 16) .push_constant(Type b
static __attribute__((constructor)) void cpu_check()
bool leak_detector_has_run
char free_after_leak_detection_message[]
void aligned_free(void *ptr)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
void *(* MEM_callocN)(size_t len, const char *str)
void * aligned_malloc(size_t size, size_t alignment)
static pthread_mutex_t thread_lock
void * MEM_guarded_mallocN_aligned(size_t len, size_t alignment, const char *str, const AllocationType allocation_type)
static void MEM_guarded_printmemlist_internal(int pydict)
void * MEM_guarded_calloc_arrayN_aligned(const size_t len, const size_t size, const size_t alignment, const char *str)
static void rem_memblock(MemHead *memh)
static const char mem_printmemlist_pydict_script[]
size_t MEM_guarded_allocN_len(const void *vmemh)
static int compare_len(const void *p1, const void *p2)
void * MEM_guarded_mallocN(size_t len, const char *str)
size_t MEM_guarded_get_peak_memory()
static int compare_name(const void *p1, const void *p2)
static void remlink(volatile localListBase *listbase, void *vlink)
struct localListBase localListBase
void * MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str)
static void make_memhead_header(MemHead *memh, size_t len, const char *str, const AllocationType allocation_type)
void MEM_guarded_reset_peak_memory()
void MEM_guarded_freeN(void *vmemh, const AllocationType allocation_type)
void MEM_guarded_set_error_callback(void(*func)(const char *))
bool MEM_guarded_consistency_check()
static bool malloc_debug_memset
struct MemPrintBlock MemPrintBlock
void MEM_guarded_printmemlist_pydict()
void MEM_guarded_callbackmemlist(void(*func)(void *))
void MEM_guarded_printmemlist()
static void(* error_callback)(const char *)
uint MEM_guarded_get_memory_blocks_in_use()
static void MemorY_ErroR(const char *block, const char *error)
static void mem_unlock_thread()
void * MEM_guarded_callocN(size_t len, const char *str)
void * MEM_guarded_reallocN_id(void *vmemh, size_t len, const char *str)
static void print_error(const char *message, va_list str_format_args)
static void report_error_on_address(const void *vmemh, const char *message,...)
void MEM_guarded_printmemlist_stats()
static const char * check_memlist(const MemHead *memh)
void * MEM_guarded_malloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_guarded_dupallocN(const void *vmemh)
size_t MEM_guarded_get_memory_in_use()
void * MEM_guarded_recallocN_id(void *vmemh, size_t len, const char *str)
static void addtail(volatile localListBase *listbase, void *vlink)
static volatile localListBase _membase
void MEM_guarded_name_ptr_set(void *vmemh, const char *str)
@ MEMHEAD_FLAG_FROM_CPP_NEW
static volatile localListBase * membase
void MEM_guarded_set_memory_debug()
const char * MEM_guarded_name_ptr(void *vmemh)
void mem_guarded_clearmemlist()
struct localLink localLink
static void mem_lock_thread()
MEM_INLINE bool MEM_size_safe_multiply(size_t a, size_t b, size_t *result)
MEM_INLINE void MEM_trigger_error_on_memory_block(const void *, const size_t)
#define MEMHEAD_REAL_PTR(memh)
#define MEMHEAD_ALIGN_PADDING(alignment)
#define SIZET_ALIGN_4(len)
#define ALIGNED_MALLOC_MINIMUM_ALIGNMENT
static void error(const char *str)
_W64 unsigned int uintptr_t