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