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);
113typedef struct MemHead {
116 MemHead *next, *prev;
118 const char *nextname;
123#ifdef DEBUG_MEMCOUNTER
127#ifdef DEBUG_MEMDUPLINAME
128 int need_free_name,
pad;
131#ifdef DEBUG_BACKTRACE_EXECINFO
132 void *backtrace[BACKTRACE_SIZE];
137static_assert(MEM_MIN_CPP_ALIGNMENT <=
alignof(MemHead),
"Bad alignment of MemHead");
138static_assert(MEM_MIN_CPP_ALIGNMENT <=
sizeof(MemHead),
"Bad size of MemHead");
140typedef MemHead MemHeadAligned;
159#ifdef DEBUG_BACKTRACE_EXECINFO
160# include <execinfo.h>
178#define MAKE_ID(a, b, c, d) (int(d) << 24 | int(c) << 16 | (b) << 8 | (a))
180#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
181#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
182#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
183#define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
185#define MEMNEXT(x) ((MemHead *)(((char *)x) - offsetof(MemHead, next)))
223 vsnprintf(buf,
sizeof(buf), message, str_format_args);
224 buf[
sizeof(buf) - 1] =
'\0';
240 va_list str_format_args;
241 va_start(str_format_args, message);
243 va_end(str_format_args);
252 va_list str_format_args;
254 va_start(str_format_args, message);
256 va_end(str_format_args);
258 if (vmemh ==
nullptr) {
263 const MemHead *memh =
static_cast<const MemHead *
>(vmemh);
265 size_t len = memh->len;
267 const void *address = memh;
269 if (
UNLIKELY(memh->alignment > 0)) {
270 const MemHeadAligned *memh_aligned = memh;
292 const char *err_val =
nullptr;
293 const MemHead *listend;
296 listend =
static_cast<MemHead *
>(
membase->last);
300 return (err_val ==
nullptr);
316 const MemHead *memh =
static_cast<const MemHead *
>(vmemh);
327 void *newp =
nullptr;
330 const MemHead *memh =
static_cast<const MemHead *
>(vmemh);
335 "Attempt to use C-style MEM_dupallocN on a pointer created with "
336 "CPP-style MEM_new or new\n");
339#ifndef DEBUG_MEMDUPLINAME
340 if (
LIKELY(memh->alignment == 0)) {
348 if (newp ==
nullptr) {
354 const char name_prefix[] =
"dupli_alloc ";
355 const size_t name_prefix_len =
sizeof(name_prefix) - 1;
356 const size_t name_size = strlen(memh->name) + 1;
357 char *
name = malloc(name_prefix_len + name_size);
358 memcpy(
name, name_prefix,
sizeof(name_prefix));
359 memcpy(
name + name_prefix_len, memh->name, name_size);
361 if (
LIKELY(memh->alignment == 0)) {
375 nmemh->need_free_name = 1;
379 memcpy(newp, vmemh, memh->len);
387 void *newp =
nullptr;
390 MemHead *memh =
static_cast<MemHead *
>(vmemh);
395 "Attempt to use C-style MEM_reallocN on a pointer created with "
396 "CPP-style MEM_new or new\n");
399 if (
LIKELY(memh->alignment == 0)) {
410 memcpy(newp, vmemh,
len);
414 memcpy(newp, vmemh, memh->len);
429 void *newp =
nullptr;
432 MemHead *memh =
static_cast<MemHead *
>(vmemh);
437 "Attempt to use C-style MEM_recallocN on a pointer created with "
438 "CPP-style MEM_new or new\n");
441 if (
LIKELY(memh->alignment == 0)) {
452 memcpy(newp, vmemh,
len);
455 memcpy(newp, vmemh, memh->len);
457 if (
len > memh->len) {
460 memset(((
char *)newp) + memh->len, 0,
len - memh->len);
474#ifdef DEBUG_BACKTRACE_EXECINFO
475static void make_memhead_backtrace(MemHead *memh)
477 memh->backtrace_size = backtrace(memh->backtrace, BACKTRACE_SIZE);
480static void print_memhead_backtrace(MemHead *memh)
485 strings = backtrace_symbols(memh->backtrace, memh->backtrace_size);
486 for (
i = 0;
i < memh->backtrace_size;
i++) {
503 memh->nextname =
nullptr;
509#ifdef DEBUG_MEMDUPLINAME
510 memh->need_free_name = 0;
513#ifdef DEBUG_BACKTRACE_EXECINFO
514 make_memhead_backtrace(memh);
517 memt = (
MemTail *)(((
char *)memh) +
sizeof(MemHead) +
len);
526 memh->nextname =
MEMNEXT(memh->next)->name;
536#ifdef WITH_MEM_VALGRIND
537 const size_t len_unaligned =
len;
541 memh = (MemHead *)malloc(
len +
sizeof(MemHead) +
sizeof(
MemTail));
548 memset(memh + 1, 255,
len);
550#ifdef WITH_MEM_VALGRIND
552 VALGRIND_MAKE_MEM_UNDEFINED(memh + 1, len_unaligned);
555 VALGRIND_MAKE_MEM_DEFINED((
const char *)(memh + 1) + len_unaligned,
len - len_unaligned);
560#ifdef DEBUG_MEMCOUNTER
561 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL) {
562 memcount_raise(__func__);
564 memh->_count = _mallocn_count++;
580 "Malloc array aborted due to integer overflow: "
620#ifdef WITH_MEM_VALGRIND
621 const size_t len_unaligned =
len;
626 len + extra_padding +
sizeof(MemHead) +
sizeof(
MemTail), alignment);
633 memh = (MemHead *)((
char *)memh + extra_padding);
636 memh->alignment = short(alignment);
639 memset(memh + 1, 255,
len);
641#ifdef WITH_MEM_VALGRIND
643 VALGRIND_MAKE_MEM_UNDEFINED(memh + 1, len_unaligned);
646 VALGRIND_MAKE_MEM_DEFINED((
const char *)(memh + 1) + len_unaligned,
len - len_unaligned);
651#ifdef DEBUG_MEMCOUNTER
652 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL) {
653 memcount_raise(__func__);
655 memh->_count = _mallocn_count++;
672 memh = (MemHead *)calloc(
len +
sizeof(MemHead) +
sizeof(
MemTail), 1);
676#ifdef DEBUG_MEMCOUNTER
677 if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL) {
678 memcount_raise(__func__);
680 memh->_count = _mallocn_count++;
696 "Calloc array aborted due to integer overflow: "
711 const size_t alignment,
717 "Calloc array aborted due to integer overflow: "
726 if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
734 const size_t alignment,
743 const size_t alignment,
753 memset(
ptr, 0, bytes_num);
769 return strcmp(pb1->
name, pb2->
name);
777 if (pb1->
len < pb2->
len) {
780 if (pb1->
len == pb2->
len) {
792 size_t mem_in_use_slop = 0;
802 print_error(
"malloc returned null while generating stats");
807 printblock =
nullptr;
813 membl =
static_cast<MemHead *
>(
membase->first);
818 while (membl && pb) {
819 pb->
name = membl->name;
820 pb->
len = membl->len;
826#ifdef USE_MALLOC_USABLE_SIZE
827 if (membl->alignment == 0) {
828 mem_in_use_slop += (
sizeof(MemHead) +
sizeof(
MemTail) + malloc_usable_size((
void *)membl)) -
846 for (a = 0,
b = 0; a < totpb; a++) {
850 if (strcmp(printblock[a].
name, printblock[
b].
name) == 0) {
851 printblock[
b].
len += printblock[a].
len;
866 printf(
"\ntotal memory len: %.3f MB\n",
double(
mem_in_use) /
double(1024 * 1024));
867 printf(
"peak memory len: %.3f MB\n",
double(
peak_mem) /
double(1024 * 1024));
868 printf(
"slop memory len: %.3f MB\n",
double(mem_in_use_slop) /
double(1024 * 1024));
869 printf(
" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
870 for (a = 0, pb = printblock; a < totpb; a++, pb++) {
871 printf(
"%6d (%8.3f %8.3f) %s\n",
873 double(pb->
len) /
double(1024 * 1024),
874 double(pb->
len) / 1024.0 /
double(pb->
items),
878 if (printblock !=
nullptr) {
884#ifdef HAVE_MALLOC_STATS
885 printf(
"System Statistics:\n");
893 "for mb_item in membase:\n"
894 " mb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
895 " mb_item_user_size[0] += 1 # Add a user\n"
896 " mb_item_user_size[1] += mb_item['len'] # Increment the size\n"
897 " totmem += mb_item['len']\n"
898 "print('(membase) items:', len(membase), '| unique-names:',\n"
899 " len(mb_userinfo), '| total-mem:', totmem)\n"
900 "mb_userinfo_sort = list(mb_userinfo.items())\n"
901 "for sort_name, sort_func in (('size', lambda a: -a[1][1]),\n"
902 " ('users', lambda a: -a[1][0]),\n"
903 " ('name', lambda a: a[0])):\n"
904 " print('\\nSorting by:', sort_name)\n"
905 " mb_userinfo_sort.sort(key = sort_func)\n"
906 " for item in mb_userinfo_sort:\n"
907 " print('name:%%s, users:%%i, len:%%i' %%\n"
908 " (item[0], item[1][0], item[1][1]))\n";
917 membl =
static_cast<MemHead *
>(
membase->first);
931 "'pointer':'%p'},\n",
934 (
void *)(membl + 1));
937#ifdef DEBUG_MEMCOUNTER
947 (
void *)(membl + 1));
950#ifdef DEBUG_BACKTRACE_EXECINFO
951 print_memhead_backtrace(membl);
952#elif defined(DEBUG_BACKTRACE) && defined(WITH_ASAN)
953 __asan_describe_address(membl);
977 membl =
static_cast<MemHead *
>(
membase->first);
996short MEM_guarded_testN(
void *vmemh)
1008 if (vmemh == membl + 1) {
1021 print_error(
"Memoryblock %p: pointer not in memlist\n", vmemh);
1042 MemHead *memh =
static_cast<MemHead *
>(vmemh);
1045 if (memh ==
nullptr) {
1046 MemorY_ErroR(
"free",
"attempt to free nullptr pointer");
1051 if (
sizeof(intptr_t) == 8) {
1052 if (intptr_t(memh) & 0x7) {
1053 MemorY_ErroR(
"free",
"attempt to free illegal pointer");
1058 if (intptr_t(memh) & 0x3) {
1059 MemorY_ErroR(
"free",
"attempt to free illegal pointer");
1071 "Attempt to use C-style MEM_freeN on a pointer created with CPP-style MEM_new or new\n");
1079 if ((memh->tag1 ==
MEMTAG1) && (memh->tag2 ==
MEMTAG2) && ((memh->len & 0x3) == 0)) {
1080 memt = (
MemTail *)(((
char *)memh) +
sizeof(MemHead) + memh->len);
1097 if (
name !=
nullptr) {
1098 if (
name != memh->name) {
1107 if (
name ==
nullptr) {
1130 if (link ==
nullptr) {
1133 if (listbase ==
nullptr) {
1138 link->
next =
nullptr;
1141 if (listbase->
last) {
1144 if (listbase->
first ==
nullptr) {
1145 listbase->
first = link;
1147 listbase->
last = link;
1157 if (link ==
nullptr) {
1160 if (listbase ==
nullptr) {
1172 if (listbase->
last == link) {
1175 if (listbase->
first == link) {
1189 MEMNEXT(memh->prev)->nextname =
nullptr;
1197#ifdef DEBUG_MEMDUPLINAME
1198 if (memh->need_free_name) {
1199 free((
char *)memh->name);
1204 memset(memh + 1, 255, memh->len);
1206 if (
LIKELY(memh->alignment == 0)) {
1218#ifdef WITH_ASSERT_ABORT
1225 MemHead *forw, *back, *forwok, *backok;
1228 forw =
static_cast<MemHead *
>(
membase->first);
1246 back = (MemHead *)
membase->last;
1265 return (
"MORE THAN 1 MEMORYBLOCK CORRUPT");
1268 if (forw ==
nullptr && back ==
nullptr) {
1271 forw =
static_cast<MemHead *
>(
membase->first);
1291 if (forw ==
nullptr) {
1295 back = (MemHead *)
membase->last;
1318 name = forwok->nextname;
1321 name =
"No name found";
1328 forwok->next = (MemHead *)&backok->next;
1329 backok->prev = (MemHead *)&forwok->next;
1330 forwok->nextname = backok->name;
1333 forwok->next =
nullptr;
1339 backok->prev =
nullptr;
1340 membase->first = &backok->next;
1349 return (
"Additional error in header");
1399 MemHead *memh =
static_cast<MemHead *
>(vmemh);
1404 return "MEM_guarded_name_ptr(nullptr)";
1413 MemHead *memh =
static_cast<MemHead *
>(vmemh);
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)]
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static __attribute__((constructor)) void cpu_check()
static int compare_name(void *user_data, const void *a1, const void *a2)
#define assert(assertion)
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 * 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)
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
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)
static void * mem_guarded_malloc_arrayN_aligned(const size_t len, const size_t size, const size_t alignment, const char *str, size_t &r_bytes_num)
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()
static void mem_lock_thread()
void * MEM_guarded_malloc_arrayN_aligned(const size_t len, const size_t size, const size_t alignment, const char *str)
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)
void *(* mem_mallocN)(size_t len, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2)