Blender  V3.3
mallocn_guarded_impl.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
10 #include <stdarg.h>
11 #include <stddef.h> /* offsetof */
12 #include <stdio.h> /* printf */
13 #include <stdlib.h>
14 #include <string.h> /* memcpy */
15 #include <sys/types.h>
16 
17 #include <pthread.h>
18 
19 #include "MEM_guardedalloc.h"
20 
21 /* to ensure strict conversions */
22 #include "../../source/blender/blenlib/BLI_strict_flags.h"
23 
24 #include "atomic_ops.h"
25 #include "mallocn_intern.h"
26 
27 /* Only for debugging:
28  * store original buffer's name when doing MEM_dupallocN
29  * helpful to profile issues with non-freed "dup_alloc" buffers,
30  * but this introduces some overhead to memory header and makes
31  * things slower a bit, so better to keep disabled by default
32  */
33 //#define DEBUG_MEMDUPLINAME
34 
35 /* Only for debugging:
36  * lets you count the allocations so as to find the allocator of unfreed memory
37  * in situations where the leak is predictable */
38 
39 //#define DEBUG_MEMCOUNTER
40 
41 /* Only for debugging:
42  * Defining DEBUG_BACKTRACE will store a backtrace from where
43  * memory block was allocated and print this trace for all
44  * unfreed blocks.
45  */
46 //#define DEBUG_BACKTRACE
47 
48 #ifdef DEBUG_BACKTRACE
49 # define BACKTRACE_SIZE 100
50 #endif
51 
52 #ifdef DEBUG_MEMCOUNTER
53 /* set this to the value that isn't being freed */
54 # define DEBUG_MEMCOUNTER_ERROR_VAL 0
55 static int _mallocn_count = 0;
56 
57 /* Break-point here. */
58 static void memcount_raise(const char *name)
59 {
60  fprintf(stderr, "%s: memcount-leak, %d\n", name, _mallocn_count);
61 }
62 #endif
63 
64 /* --------------------------------------------------------------------- */
65 /* Data definition */
66 /* --------------------------------------------------------------------- */
67 /* all memory chunks are put in linked lists */
68 typedef struct localLink {
69  struct localLink *next, *prev;
71 
72 typedef struct localListBase {
73  void *first, *last;
75 
76 /* NOTE(@hos): keep this struct aligned (e.g., IRIX/GCC). */
77 typedef struct MemHead {
78  int tag1;
79  size_t len;
80  struct MemHead *next, *prev;
81  const char *name;
82  const char *nextname;
83  int tag2;
84  short pad1;
85  /* if non-zero aligned allocation was used and alignment is stored here. */
86  short alignment;
87 #ifdef DEBUG_MEMCOUNTER
88  int _count;
89 #endif
90 
91 #ifdef DEBUG_MEMDUPLINAME
92  int need_free_name, pad;
93 #endif
94 
95 #ifdef DEBUG_BACKTRACE
96  void *backtrace[BACKTRACE_SIZE];
97  int backtrace_size;
98 #endif
100 
102 
103 #ifdef DEBUG_BACKTRACE
104 # if defined(__linux__) || defined(__APPLE__)
105 # include <execinfo.h>
106 // Windows is not supported yet.
107 //# elif defined(_MSV_VER)
108 //# include <DbgHelp.h>
109 # endif
110 #endif
111 
112 typedef struct MemTail {
113  int tag3, pad;
115 
116 /* --------------------------------------------------------------------- */
117 /* local functions */
118 /* --------------------------------------------------------------------- */
119 
120 static void addtail(volatile localListBase *listbase, void *vlink);
121 static void remlink(volatile localListBase *listbase, void *vlink);
122 static void rem_memblock(MemHead *memh);
123 static void MemorY_ErroR(const char *block, const char *error);
124 static const char *check_memlist(MemHead *memh);
125 
126 /* --------------------------------------------------------------------- */
127 /* locally used defines */
128 /* --------------------------------------------------------------------- */
129 
130 #ifdef __BIG_ENDIAN__
131 # define MAKE_ID(a, b, c, d) ((int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d))
132 #else
133 # define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
134 #endif
135 
136 #define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
137 #define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
138 #define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
139 #define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
140 
141 #define MEMNEXT(x) ((MemHead *)(((char *)x) - offsetof(MemHead, next)))
142 
143 /* --------------------------------------------------------------------- */
144 /* vars */
145 /* --------------------------------------------------------------------- */
146 
147 static unsigned int totblock = 0;
148 static size_t mem_in_use = 0, peak_mem = 0;
149 
150 static volatile struct localListBase _membase;
151 static volatile struct localListBase *membase = &_membase;
152 static void (*error_callback)(const char *) = NULL;
153 
154 static bool malloc_debug_memset = false;
155 
156 #ifdef malloc
157 # undef malloc
158 #endif
159 
160 #ifdef calloc
161 # undef calloc
162 #endif
163 
164 #ifdef free
165 # undef free
166 #endif
167 
168 /* --------------------------------------------------------------------- */
169 /* implementation */
170 /* --------------------------------------------------------------------- */
171 
172 #ifdef __GNUC__
173 __attribute__((format(printf, 1, 2)))
174 #endif
175 static void
176 print_error(const char *str, ...)
177 {
178  char buf[1024];
179  va_list ap;
180 
181  va_start(ap, str);
182  vsnprintf(buf, sizeof(buf), str, ap);
183  va_end(ap);
184  buf[sizeof(buf) - 1] = '\0';
185 
186  if (error_callback) {
187  error_callback(buf);
188  }
189  else {
190  fputs(buf, stderr);
191  }
192 }
193 
194 static pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER;
195 
196 static void mem_lock_thread(void)
197 {
198  pthread_mutex_lock(&thread_lock);
199 }
200 
201 static void mem_unlock_thread(void)
202 {
203  pthread_mutex_unlock(&thread_lock);
204 }
205 
207 {
208  const char *err_val = NULL;
209  MemHead *listend;
210  /* check_memlist starts from the front, and runs until it finds
211  * the requested chunk. For this test, that's the last one. */
212  listend = membase->last;
213 
214  err_val = check_memlist(listend);
215 
216  return (err_val == NULL);
217 }
218 
219 void MEM_guarded_set_error_callback(void (*func)(const char *))
220 {
221  error_callback = func;
222 }
223 
225 {
226  malloc_debug_memset = true;
227 }
228 
229 size_t MEM_guarded_allocN_len(const void *vmemh)
230 {
231  if (vmemh) {
232  const MemHead *memh = vmemh;
233 
234  memh--;
235  return memh->len;
236  }
237 
238  return 0;
239 }
240 
241 void *MEM_guarded_dupallocN(const void *vmemh)
242 {
243  void *newp = NULL;
244 
245  if (vmemh) {
246  const MemHead *memh = vmemh;
247  memh--;
248 
249 #ifndef DEBUG_MEMDUPLINAME
250  if (LIKELY(memh->alignment == 0)) {
251  newp = MEM_guarded_mallocN(memh->len, "dupli_alloc");
252  }
253  else {
254  newp = MEM_guarded_mallocN_aligned(memh->len, (size_t)memh->alignment, "dupli_alloc");
255  }
256 
257  if (newp == NULL) {
258  return NULL;
259  }
260 #else
261  {
262  MemHead *nmemh;
263  char *name = malloc(strlen(memh->name) + 24);
264 
265  if (LIKELY(memh->alignment == 0)) {
266  sprintf(name, "%s %s", "dupli_alloc", memh->name);
267  newp = MEM_guarded_mallocN(memh->len, name);
268  }
269  else {
270  sprintf(name, "%s %s", "dupli_alloc", memh->name);
271  newp = MEM_guarded_mallocN_aligned(memh->len, (size_t)memh->alignment, name);
272  }
273 
274  if (newp == NULL)
275  return NULL;
276 
277  nmemh = newp;
278  nmemh--;
279 
280  nmemh->need_free_name = 1;
281  }
282 #endif
283 
284  memcpy(newp, vmemh, memh->len);
285  }
286 
287  return newp;
288 }
289 
290 void *MEM_guarded_reallocN_id(void *vmemh, size_t len, const char *str)
291 {
292  void *newp = NULL;
293 
294  if (vmemh) {
295  MemHead *memh = vmemh;
296  memh--;
297 
298  if (LIKELY(memh->alignment == 0)) {
299  newp = MEM_guarded_mallocN(len, memh->name);
300  }
301  else {
302  newp = MEM_guarded_mallocN_aligned(len, (size_t)memh->alignment, memh->name);
303  }
304 
305  if (newp) {
306  if (len < memh->len) {
307  /* shrink */
308  memcpy(newp, vmemh, len);
309  }
310  else {
311  /* grow (or remain same size) */
312  memcpy(newp, vmemh, memh->len);
313  }
314  }
315 
316  MEM_guarded_freeN(vmemh);
317  }
318  else {
319  newp = MEM_guarded_mallocN(len, str);
320  }
321 
322  return newp;
323 }
324 
325 void *MEM_guarded_recallocN_id(void *vmemh, size_t len, const char *str)
326 {
327  void *newp = NULL;
328 
329  if (vmemh) {
330  MemHead *memh = vmemh;
331  memh--;
332 
333  if (LIKELY(memh->alignment == 0)) {
334  newp = MEM_guarded_mallocN(len, memh->name);
335  }
336  else {
337  newp = MEM_guarded_mallocN_aligned(len, (size_t)memh->alignment, memh->name);
338  }
339 
340  if (newp) {
341  if (len < memh->len) {
342  /* shrink */
343  memcpy(newp, vmemh, len);
344  }
345  else {
346  memcpy(newp, vmemh, memh->len);
347 
348  if (len > memh->len) {
349  /* grow */
350  /* zero new bytes */
351  memset(((char *)newp) + memh->len, 0, len - memh->len);
352  }
353  }
354  }
355 
356  MEM_guarded_freeN(vmemh);
357  }
358  else {
359  newp = MEM_guarded_callocN(len, str);
360  }
361 
362  return newp;
363 }
364 
365 #ifdef DEBUG_BACKTRACE
366 # if defined(__linux__) || defined(__APPLE__)
367 static void make_memhead_backtrace(MemHead *memh)
368 {
369  memh->backtrace_size = backtrace(memh->backtrace, BACKTRACE_SIZE);
370 }
371 
372 static void print_memhead_backtrace(MemHead *memh)
373 {
374  char **strings;
375  int i;
376 
377  strings = backtrace_symbols(memh->backtrace, memh->backtrace_size);
378  for (i = 0; i < memh->backtrace_size; i++) {
379  print_error(" %s\n", strings[i]);
380  }
381 
382  free(strings);
383 }
384 # else
385 static void make_memhead_backtrace(MemHead *memh)
386 {
387  (void)memh; /* Ignored. */
388 }
389 
390 static void print_memhead_backtrace(MemHead *memh)
391 {
392  (void)memh; /* Ignored. */
393 }
394 # endif /* defined(__linux__) || defined(__APPLE__) */
395 #endif /* DEBUG_BACKTRACE */
396 
397 static void make_memhead_header(MemHead *memh, size_t len, const char *str)
398 {
399  MemTail *memt;
400 
401  memh->tag1 = MEMTAG1;
402  memh->name = str;
403  memh->nextname = NULL;
404  memh->len = len;
405  memh->pad1 = 0;
406  memh->alignment = 0;
407  memh->tag2 = MEMTAG2;
408 
409 #ifdef DEBUG_MEMDUPLINAME
410  memh->need_free_name = 0;
411 #endif
412 
413 #ifdef DEBUG_BACKTRACE
414  make_memhead_backtrace(memh);
415 #endif
416 
417  memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + len);
418  memt->tag3 = MEMTAG3;
419 
422 
423  mem_lock_thread();
424  addtail(membase, &memh->next);
425  if (memh->next) {
426  memh->nextname = MEMNEXT(memh->next)->name;
427  }
430 }
431 
432 void *MEM_guarded_mallocN(size_t len, const char *str)
433 {
434  MemHead *memh;
435 
436  len = SIZET_ALIGN_4(len);
437 
438  memh = (MemHead *)malloc(len + sizeof(MemHead) + sizeof(MemTail));
439 
440  if (LIKELY(memh)) {
441  make_memhead_header(memh, len, str);
442  if (UNLIKELY(malloc_debug_memset && len)) {
443  memset(memh + 1, 255, len);
444  }
445 
446 #ifdef DEBUG_MEMCOUNTER
447  if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
448  memcount_raise(__func__);
449  memh->_count = _mallocn_count++;
450 #endif
451  return (++memh);
452  }
453  print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
454  SIZET_ARG(len),
455  str,
456  (unsigned int)mem_in_use);
457  return NULL;
458 }
459 
460 void *MEM_guarded_malloc_arrayN(size_t len, size_t size, const char *str)
461 {
462  size_t total_size;
463  if (UNLIKELY(!MEM_size_safe_multiply(len, size, &total_size))) {
464  print_error(
465  "Malloc array aborted due to integer overflow: "
466  "len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total %u\n",
467  SIZET_ARG(len),
468  SIZET_ARG(size),
469  str,
470  (unsigned int)mem_in_use);
471  abort();
472  return NULL;
473  }
474 
475  return MEM_guarded_mallocN(total_size, str);
476 }
477 
478 void *MEM_guarded_mallocN_aligned(size_t len, size_t alignment, const char *str)
479 {
480  /* We only support alignment to a power of two. */
481  assert(IS_POW2(alignment));
482 
483  /* Use a minimal alignment of 8. Otherwise MEM_guarded_freeN thinks it is an illegal pointer. */
484  if (alignment < 8) {
485  alignment = 8;
486  }
487 
488  /* It's possible that MemHead's size is not properly aligned,
489  * do extra padding to deal with this.
490  *
491  * We only support small alignments which fits into short in
492  * order to save some bits in MemHead structure.
493  */
494  size_t extra_padding = MEMHEAD_ALIGN_PADDING(alignment);
495 
496  /* Huge alignment values doesn't make sense and they
497  * wouldn't fit into 'short' used in the MemHead.
498  */
499  assert(alignment < 1024);
500 
501  len = SIZET_ALIGN_4(len);
502 
503  MemHead *memh = (MemHead *)aligned_malloc(
504  len + extra_padding + sizeof(MemHead) + sizeof(MemTail), alignment);
505 
506  if (LIKELY(memh)) {
507  /* We keep padding in the beginning of MemHead,
508  * this way it's always possible to get MemHead
509  * from the data pointer.
510  */
511  memh = (MemHead *)((char *)memh + extra_padding);
512 
513  make_memhead_header(memh, len, str);
514  memh->alignment = (short)alignment;
515  if (UNLIKELY(malloc_debug_memset && len)) {
516  memset(memh + 1, 255, len);
517  }
518 
519 #ifdef DEBUG_MEMCOUNTER
520  if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
521  memcount_raise(__func__);
522  memh->_count = _mallocn_count++;
523 #endif
524  return (++memh);
525  }
526  print_error("aligned_malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
527  SIZET_ARG(len),
528  str,
529  (unsigned int)mem_in_use);
530  return NULL;
531 }
532 
533 void *MEM_guarded_callocN(size_t len, const char *str)
534 {
535  MemHead *memh;
536 
537  len = SIZET_ALIGN_4(len);
538 
539  memh = (MemHead *)calloc(len + sizeof(MemHead) + sizeof(MemTail), 1);
540 
541  if (memh) {
542  make_memhead_header(memh, len, str);
543 #ifdef DEBUG_MEMCOUNTER
544  if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
545  memcount_raise(__func__);
546  memh->_count = _mallocn_count++;
547 #endif
548  return (++memh);
549  }
550  print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
551  SIZET_ARG(len),
552  str,
553  (unsigned int)mem_in_use);
554  return NULL;
555 }
556 
557 void *MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str)
558 {
559  size_t total_size;
560  if (UNLIKELY(!MEM_size_safe_multiply(len, size, &total_size))) {
561  print_error(
562  "Calloc array aborted due to integer overflow: "
563  "len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total %u\n",
564  SIZET_ARG(len),
565  SIZET_ARG(size),
566  str,
567  (unsigned int)mem_in_use);
568  abort();
569  return NULL;
570  }
571 
572  return MEM_guarded_callocN(total_size, str);
573 }
574 
575 /* Memory statistics print */
576 typedef struct MemPrintBlock {
577  const char *name;
579  int items;
581 
582 static int compare_name(const void *p1, const void *p2)
583 {
584  const MemPrintBlock *pb1 = (const MemPrintBlock *)p1;
585  const MemPrintBlock *pb2 = (const MemPrintBlock *)p2;
586 
587  return strcmp(pb1->name, pb2->name);
588 }
589 
590 static int compare_len(const void *p1, const void *p2)
591 {
592  const MemPrintBlock *pb1 = (const MemPrintBlock *)p1;
593  const MemPrintBlock *pb2 = (const MemPrintBlock *)p2;
594 
595  if (pb1->len < pb2->len) {
596  return 1;
597  }
598  if (pb1->len == pb2->len) {
599  return 0;
600  }
601 
602  return -1;
603 }
604 
606 {
607  MemHead *membl;
608  MemPrintBlock *pb, *printblock;
609  unsigned int totpb, a, b;
610  size_t mem_in_use_slop = 0;
611 
612  mem_lock_thread();
613 
614  if (totblock != 0) {
615  /* put memory blocks into array */
616  printblock = malloc(sizeof(MemPrintBlock) * totblock);
617 
618  if (UNLIKELY(!printblock)) {
620  print_error("malloc returned null while generating stats");
621  return;
622  }
623  }
624  else {
625  printblock = NULL;
626  }
627 
628  pb = printblock;
629  totpb = 0;
630 
631  membl = membase->first;
632  if (membl) {
633  membl = MEMNEXT(membl);
634  }
635 
636  while (membl && pb) {
637  pb->name = membl->name;
638  pb->len = membl->len;
639  pb->items = 1;
640 
641  totpb++;
642  pb++;
643 
644 #ifdef USE_MALLOC_USABLE_SIZE
645  if (membl->alignment == 0) {
646  mem_in_use_slop += (sizeof(MemHead) + sizeof(MemTail) + malloc_usable_size((void *)membl)) -
647  membl->len;
648  }
649 #endif
650 
651  if (membl->next) {
652  membl = MEMNEXT(membl->next);
653  }
654  else {
655  break;
656  }
657  }
658 
659  /* sort by name and add together blocks with the same name */
660  if (totpb > 1) {
661  qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
662  }
663 
664  for (a = 0, b = 0; a < totpb; a++) {
665  if (a == b) {
666  continue;
667  }
668  if (strcmp(printblock[a].name, printblock[b].name) == 0) {
669  printblock[b].len += printblock[a].len;
670  printblock[b].items++;
671  }
672  else {
673  b++;
674  memcpy(&printblock[b], &printblock[a], sizeof(MemPrintBlock));
675  }
676  }
677  totpb = b + 1;
678 
679  /* sort by length and print */
680  if (totpb > 1) {
681  qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
682  }
683 
684  printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use / (double)(1024 * 1024));
685  printf("peak memory len: %.3f MB\n", (double)peak_mem / (double)(1024 * 1024));
686  printf("slop memory len: %.3f MB\n", (double)mem_in_use_slop / (double)(1024 * 1024));
687  printf(" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
688  for (a = 0, pb = printblock; a < totpb; a++, pb++) {
689  printf("%6d (%8.3f %8.3f) %s\n",
690  pb->items,
691  (double)pb->len / (double)(1024 * 1024),
692  (double)pb->len / 1024.0 / (double)pb->items,
693  pb->name);
694  }
695 
696  if (printblock != NULL) {
697  free(printblock);
698  }
699 
701 
702 #ifdef HAVE_MALLOC_STATS
703  printf("System Statistics:\n");
704  malloc_stats();
705 #endif
706 }
707 
708 static const char mem_printmemlist_pydict_script[] =
709  "mb_userinfo = {}\n"
710  "totmem = 0\n"
711  "for mb_item in membase:\n"
712  " mb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
713  " mb_item_user_size[0] += 1 # Add a user\n"
714  " mb_item_user_size[1] += mb_item['len'] # Increment the size\n"
715  " totmem += mb_item['len']\n"
716  "print('(membase) items:', len(membase), '| unique-names:',\n"
717  " len(mb_userinfo), '| total-mem:', totmem)\n"
718  "mb_userinfo_sort = list(mb_userinfo.items())\n"
719  "for sort_name, sort_func in (('size', lambda a: -a[1][1]),\n"
720  " ('users', lambda a: -a[1][0]),\n"
721  " ('name', lambda a: a[0])):\n"
722  " print('\\nSorting by:', sort_name)\n"
723  " mb_userinfo_sort.sort(key = sort_func)\n"
724  " for item in mb_userinfo_sort:\n"
725  " print('name:%%s, users:%%i, len:%%i' %%\n"
726  " (item[0], item[1][0], item[1][1]))\n";
727 
728 /* Prints in python syntax for easy */
729 static void MEM_guarded_printmemlist_internal(int pydict)
730 {
731  MemHead *membl;
732 
733  mem_lock_thread();
734 
735  membl = membase->first;
736  if (membl) {
737  membl = MEMNEXT(membl);
738  }
739 
740  if (pydict) {
741  print_error("# membase_debug.py\n");
742  print_error("membase = [\n");
743  }
744  while (membl) {
745  if (pydict) {
746  print_error(" {'len':" SIZET_FORMAT
747  ", "
748  "'name':'''%s''', "
749  "'pointer':'%p'},\n",
750  SIZET_ARG(membl->len),
751  membl->name,
752  (void *)(membl + 1));
753  }
754  else {
755 #ifdef DEBUG_MEMCOUNTER
756  print_error("%s len: " SIZET_FORMAT " %p, count: %d\n",
757  membl->name,
758  SIZET_ARG(membl->len),
759  membl + 1,
760  membl->_count);
761 #else
762  print_error("%s len: " SIZET_FORMAT " %p\n",
763  membl->name,
764  SIZET_ARG(membl->len),
765  (void *)(membl + 1));
766 #endif
767 #ifdef DEBUG_BACKTRACE
768  print_memhead_backtrace(membl);
769 #endif
770  }
771  if (membl->next) {
772  membl = MEMNEXT(membl->next);
773  }
774  else {
775  break;
776  }
777  }
778  if (pydict) {
779  print_error("]\n\n");
781  }
782 
784 }
785 
786 void MEM_guarded_callbackmemlist(void (*func)(void *))
787 {
788  MemHead *membl;
789 
790  mem_lock_thread();
791 
792  membl = membase->first;
793  if (membl) {
794  membl = MEMNEXT(membl);
795  }
796 
797  while (membl) {
798  func(membl + 1);
799  if (membl->next) {
800  membl = MEMNEXT(membl->next);
801  }
802  else {
803  break;
804  }
805  }
806 
808 }
809 
810 #if 0
811 short MEM_guarded_testN(void *vmemh)
812 {
813  MemHead *membl;
814 
815  mem_lock_thread();
816 
817  membl = membase->first;
818  if (membl)
819  membl = MEMNEXT(membl);
820 
821  while (membl) {
822  if (vmemh == membl + 1) {
824  return 1;
825  }
826 
827  if (membl->next)
828  membl = MEMNEXT(membl->next);
829  else
830  break;
831  }
832 
834 
835  print_error("Memoryblock %p: pointer not in memlist\n", vmemh);
836  return 0;
837 }
838 #endif
839 
841 {
843 }
845 {
847 }
848 
849 void MEM_guarded_freeN(void *vmemh)
850 {
851  MemTail *memt;
852  MemHead *memh = vmemh;
853  const char *name;
854 
855  if (memh == NULL) {
856  MemorY_ErroR("free", "attempt to free NULL pointer");
857  // print_error(err_stream, "%d\n", (memh+4000)->tag1);
858  return;
859  }
860 
861  if (sizeof(intptr_t) == 8) {
862  if (((intptr_t)memh) & 0x7) {
863  MemorY_ErroR("free", "attempt to free illegal pointer");
864  return;
865  }
866  }
867  else {
868  if (((intptr_t)memh) & 0x3) {
869  MemorY_ErroR("free", "attempt to free illegal pointer");
870  return;
871  }
872  }
873 
874  memh--;
875  if (memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
876  MemorY_ErroR(memh->name, "double free");
877  return;
878  }
879 
880  if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
881  memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + memh->len);
882  if (memt->tag3 == MEMTAG3) {
883 
884  if (leak_detector_has_run) {
886  }
887 
888  memh->tag1 = MEMFREE;
889  memh->tag2 = MEMFREE;
890  memt->tag3 = MEMFREE;
891  /* after tags !!! */
892  rem_memblock(memh);
893 
894  return;
895  }
896  MemorY_ErroR(memh->name, "end corrupt");
897  name = check_memlist(memh);
898  if (name != NULL) {
899  if (name != memh->name) {
900  MemorY_ErroR(name, "is also corrupt");
901  }
902  }
903  }
904  else {
905  mem_lock_thread();
906  name = check_memlist(memh);
908  if (name == NULL) {
909  MemorY_ErroR("free", "pointer not in memlist");
910  }
911  else {
912  MemorY_ErroR(name, "error in header");
913  }
914  }
915 
916  totblock--;
917  /* here a DUMP should happen */
918 }
919 
920 /* --------------------------------------------------------------------- */
921 /* local functions */
922 /* --------------------------------------------------------------------- */
923 
924 static void addtail(volatile localListBase *listbase, void *vlink)
925 {
926  struct localLink *link = vlink;
927 
928  /* for a generic API error checks here is fine but
929  * the limited use here they will never be NULL */
930 #if 0
931  if (link == NULL)
932  return;
933  if (listbase == NULL)
934  return;
935 #endif
936 
937  link->next = NULL;
938  link->prev = listbase->last;
939 
940  if (listbase->last) {
941  ((struct localLink *)listbase->last)->next = link;
942  }
943  if (listbase->first == NULL) {
944  listbase->first = link;
945  }
946  listbase->last = link;
947 }
948 
949 static void remlink(volatile localListBase *listbase, void *vlink)
950 {
951  struct localLink *link = vlink;
952 
953  /* for a generic API error checks here is fine but
954  * the limited use here they will never be NULL */
955 #if 0
956  if (link == NULL)
957  return;
958  if (listbase == NULL)
959  return;
960 #endif
961 
962  if (link->next) {
963  link->next->prev = link->prev;
964  }
965  if (link->prev) {
966  link->prev->next = link->next;
967  }
968 
969  if (listbase->last == link) {
970  listbase->last = link->prev;
971  }
972  if (listbase->first == link) {
973  listbase->first = link->next;
974  }
975 }
976 
977 static void rem_memblock(MemHead *memh)
978 {
979  mem_lock_thread();
980  remlink(membase, &memh->next);
981  if (memh->prev) {
982  if (memh->next) {
983  MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
984  }
985  else {
986  MEMNEXT(memh->prev)->nextname = NULL;
987  }
988  }
990 
993 
994 #ifdef DEBUG_MEMDUPLINAME
995  if (memh->need_free_name)
996  free((char *)memh->name);
997 #endif
998 
999  if (UNLIKELY(malloc_debug_memset && memh->len)) {
1000  memset(memh + 1, 255, memh->len);
1001  }
1002  if (LIKELY(memh->alignment == 0)) {
1003  free(memh);
1004  }
1005  else {
1007  }
1008 }
1009 
1010 static void MemorY_ErroR(const char *block, const char *error)
1011 {
1012  print_error("Memoryblock %s: %s\n", block, error);
1013 
1014 #ifdef WITH_ASSERT_ABORT
1015  abort();
1016 #endif
1017 }
1018 
1019 static const char *check_memlist(MemHead *memh)
1020 {
1021  MemHead *forw, *back, *forwok, *backok;
1022  const char *name;
1023 
1024  forw = membase->first;
1025  if (forw) {
1026  forw = MEMNEXT(forw);
1027  }
1028  forwok = NULL;
1029  while (forw) {
1030  if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) {
1031  break;
1032  }
1033  forwok = forw;
1034  if (forw->next) {
1035  forw = MEMNEXT(forw->next);
1036  }
1037  else {
1038  forw = NULL;
1039  }
1040  }
1041 
1042  back = (MemHead *)membase->last;
1043  if (back) {
1044  back = MEMNEXT(back);
1045  }
1046  backok = NULL;
1047  while (back) {
1048  if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) {
1049  break;
1050  }
1051  backok = back;
1052  if (back->prev) {
1053  back = MEMNEXT(back->prev);
1054  }
1055  else {
1056  back = NULL;
1057  }
1058  }
1059 
1060  if (forw != back) {
1061  return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
1062  }
1063 
1064  if (forw == NULL && back == NULL) {
1065  /* no wrong headers found then but in search of memblock */
1066 
1067  forw = membase->first;
1068  if (forw) {
1069  forw = MEMNEXT(forw);
1070  }
1071  forwok = NULL;
1072  while (forw) {
1073  if (forw == memh) {
1074  break;
1075  }
1076  if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) {
1077  break;
1078  }
1079  forwok = forw;
1080  if (forw->next) {
1081  forw = MEMNEXT(forw->next);
1082  }
1083  else {
1084  forw = NULL;
1085  }
1086  }
1087  if (forw == NULL) {
1088  return NULL;
1089  }
1090 
1091  back = (MemHead *)membase->last;
1092  if (back) {
1093  back = MEMNEXT(back);
1094  }
1095  backok = NULL;
1096  while (back) {
1097  if (back == memh) {
1098  break;
1099  }
1100  if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) {
1101  break;
1102  }
1103  backok = back;
1104  if (back->prev) {
1105  back = MEMNEXT(back->prev);
1106  }
1107  else {
1108  back = NULL;
1109  }
1110  }
1111  }
1112 
1113  if (forwok) {
1114  name = forwok->nextname;
1115  }
1116  else {
1117  name = "No name found";
1118  }
1119 
1120  if (forw == memh) {
1121  /* to be sure but this block is removed from the list */
1122  if (forwok) {
1123  if (backok) {
1124  forwok->next = (MemHead *)&backok->next;
1125  backok->prev = (MemHead *)&forwok->next;
1126  forwok->nextname = backok->name;
1127  }
1128  else {
1129  forwok->next = NULL;
1130  membase->last = (struct localLink *)&forwok->next;
1131  }
1132  }
1133  else {
1134  if (backok) {
1135  backok->prev = NULL;
1136  membase->first = &backok->next;
1137  }
1138  else {
1139  membase->first = membase->last = NULL;
1140  }
1141  }
1142  }
1143  else {
1144  MemorY_ErroR(name, "Additional error in header");
1145  return ("Additional error in header");
1146  }
1147 
1148  return name;
1149 }
1150 
1152 {
1153  size_t _peak_mem;
1154 
1155  mem_lock_thread();
1156  _peak_mem = peak_mem;
1158 
1159  return _peak_mem;
1160 }
1161 
1163 {
1164  mem_lock_thread();
1165  peak_mem = mem_in_use;
1167 }
1168 
1170 {
1171  size_t _mem_in_use;
1172 
1173  mem_lock_thread();
1174  _mem_in_use = mem_in_use;
1176 
1177  return _mem_in_use;
1178 }
1179 
1181 {
1182  unsigned int _totblock;
1183 
1184  mem_lock_thread();
1185  _totblock = totblock;
1187 
1188  return _totblock;
1189 }
1190 
1191 #ifndef NDEBUG
1192 const char *MEM_guarded_name_ptr(void *vmemh)
1193 {
1194  if (vmemh) {
1195  MemHead *memh = vmemh;
1196  memh--;
1197  return memh->name;
1198  }
1199 
1200  return "MEM_guarded_name_ptr(NULL)";
1201 }
1202 #endif /* NDEBUG */
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
#define UNLIKELY(x)
#define LIKELY(x)
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)
struct AtomicSpinLock __attribute__((aligned(32))) AtomicSpinLock
int pad[32 - sizeof(int)]
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
#define str(s)
bool leak_detector_has_run
char free_after_leak_detection_message[]
format
Definition: logImageCore.h:38
void aligned_free(void *ptr)
Definition: mallocn.c:76
void * aligned_malloc(size_t size, size_t alignment)
Definition: mallocn.c:54
static pthread_mutex_t thread_lock
static void MEM_guarded_printmemlist_internal(int pydict)
static void rem_memblock(MemHead *memh)
static const char mem_printmemlist_pydict_script[]
size_t MEM_guarded_allocN_len(const void *vmemh)
const char * MEM_guarded_name_ptr(void *vmemh)
unsigned int MEM_guarded_get_memory_blocks_in_use(void)
struct MemTail MemTail
static volatile struct localListBase * membase
static size_t mem_in_use
static int compare_len(const void *p1, const void *p2)
static int compare_name(const void *p1, const void *p2)
static volatile struct localListBase _membase
void * MEM_guarded_callocN(size_t len, const char *str)
static void remlink(volatile localListBase *listbase, void *vlink)
struct localListBase localListBase
static size_t peak_mem
void * MEM_guarded_dupallocN(const void *vmemh)
void * MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str)
void MEM_guarded_set_error_callback(void(*func)(const char *))
#define MEMNEXT(x)
void MEM_guarded_printmemlist(void)
void MEM_guarded_printmemlist_pydict(void)
static bool malloc_debug_memset
struct MemPrintBlock MemPrintBlock
#define MEMTAG2
void MEM_guarded_callbackmemlist(void(*func)(void *))
MemHead MemHeadAligned
static unsigned int totblock
static void(* error_callback)(const char *)
static void MemorY_ErroR(const char *block, const char *error)
bool MEM_guarded_consistency_check(void)
static void mem_unlock_thread(void)
static void mem_lock_thread(void)
void MEM_guarded_set_memory_debug(void)
static void print_error(const char *str,...)
void MEM_guarded_printmemlist_stats(void)
struct MemHead MemHead
#define MEMFREE
static void make_memhead_header(MemHead *memh, size_t len, const char *str)
size_t MEM_guarded_get_peak_memory(void)
#define MEMTAG3
static void addtail(volatile localListBase *listbase, void *vlink)
void * MEM_guarded_malloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_guarded_mallocN(size_t len, const char *str)
void * MEM_guarded_mallocN_aligned(size_t len, size_t alignment, const char *str)
void * MEM_guarded_reallocN_id(void *vmemh, size_t len, const char *str)
void * MEM_guarded_recallocN_id(void *vmemh, size_t len, const char *str)
void MEM_guarded_reset_peak_memory(void)
struct localLink localLink
size_t MEM_guarded_get_memory_in_use(void)
static const char * check_memlist(MemHead *memh)
void MEM_guarded_freeN(void *vmemh)
#define MEMTAG1
MEM_INLINE bool MEM_size_safe_multiply(size_t a, size_t b, size_t *result)
#define MEMHEAD_REAL_PTR(memh)
#define IS_POW2(a)
#define MEMHEAD_ALIGN_PADDING(alignment)
#define SIZET_ARG(a)
#define SIZET_ALIGN_4(len)
#define SIZET_FORMAT
static void error(const char *str)
Definition: meshlaplacian.c:51
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
_W64 unsigned int uintptr_t
Definition: stdint.h:119
_W64 int intptr_t
Definition: stdint.h:118
const char * name
struct MemHead * prev
struct MemHead * next
const char * nextname