HPCToolkit
memleak-overrides.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 // MEMLEAK overrides the malloc family of functions and provides two
48 // metrics: number of bytes allocated and number of bytes freed per
49 // dynamic context. Subtracting these two values is a way to find
50 // memory leaks.
51 //
52 // Override functions:
53 // posix_memalign, memalign, valloc
54 // malloc, calloc, free, realloc
55 
56 /******************************************************************************
57  * standard include files
58  *****************************************************************************/
59 
60 #define __USE_XOPEN_EXTENDED
61 #include <sys/stat.h>
62 #include <sys/time.h>
63 #include <sys/types.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <stdint.h>
68 #include <string.h>
69 #include <ucontext.h>
70 
71 /* definition for posix memalign */
72 #undef _XOPEN_SOURCE // avoid complaint about redefinition
73 #define _XOPEN_SOURCE 600
74 #include <stdlib.h>
75 
76 /* definition for valloc, memalign */
77 #include <malloc.h>
78 
79 /* definition for sysconf */
80 #include <unistd.h>
81 
82 /* definition for _SC_PAGESIZE */
83 #include <sys/mman.h>
84 
85 
86 
87 /******************************************************************************
88  * local include files
89  *****************************************************************************/
90 
91 #include <sample-sources/memleak.h>
92 #include <messages/messages.h>
93 #include <safe-sampling.h>
94 #include <sample_event.h>
96 #include <lib/prof-lean/spinlock.h>
98 
99 // FIXME: the inline getcontext macro is broken on 32-bit x86, so
100 // revert to the getcontext syscall for now.
101 #if defined(__i386__)
102 #ifndef USE_SYS_GCTXT
103 #define USE_SYS_GCTXT
104 #endif
105 #else // ! __i386__
107 #include <utilities/arch/mcontext.h>
108 #endif
109 
110 
111 /******************************************************************************
112  * type definitions
113  *****************************************************************************/
114 
115 typedef struct leakinfo_s {
116  long magic;
118  size_t bytes;
119  void *memblock;
120  struct leakinfo_s *left;
121  struct leakinfo_s *right;
122 } leakinfo_t;
123 
124 leakinfo_t leakinfo_NULL = { .magic = 0, .context = NULL, .bytes = 0 };
125 
126 typedef void *memalign_fcn(size_t, size_t);
127 typedef void *valloc_fcn(size_t);
128 typedef void *malloc_fcn(size_t);
129 typedef void free_fcn(void *);
130 typedef void *realloc_fcn(void *, size_t);
131 
132 
133 
134 /******************************************************************************
135  * macros
136  *****************************************************************************/
137 
138 #define MEMLEAK_USE_HYBRID_LAYOUT 1
139 
140 #define MEMLEAK_MAGIC 0x68706374
141 #define MEMLEAK_DEFAULT_PAGESIZE 4096
142 
143 #define HPCRUN_MEMLEAK_PROB "HPCRUN_MEMLEAK_PROB"
144 #define DEFAULT_PROB 0.1
145 
146 #ifdef HPCRUN_STATIC_LINK
147 #define real_memalign __real_memalign
148 #define real_valloc __real_valloc
149 #define real_malloc __real_malloc
150 #define real_free __real_free
151 #define real_realloc __real_realloc
152 #else
153 #define real_memalign __libc_memalign
154 #define real_valloc __libc_valloc
155 #define real_malloc __libc_malloc
156 #define real_free __libc_free
157 #define real_realloc __libc_realloc
158 #endif
159 
161 extern valloc_fcn real_valloc;
162 extern malloc_fcn real_malloc;
163 extern free_fcn real_free;
165 
166 
167 
168 /******************************************************************************
169  * private data
170  *****************************************************************************/
171 
172 static int leak_detection_enabled = 0; // default is off
173 static int leak_detection_init = 0; // default is uninitialized
174 static int use_memleak_prob = 0;
175 static float memleak_prob = 0.0;
176 
179 
180 static int leakinfo_size = sizeof(struct leakinfo_s);
182 
183 enum {
187 };
188 
189 static char *loc_name[4] = {
190  NULL, "header", "footer", "none"
191 };
192 
193 
194 
195 /******************************************************************************
196  * splay operations
197  *****************************************************************************/
198 
199 
200 static struct leakinfo_s *
201 splay(struct leakinfo_s *root, void *key)
202 {
204  return root;
205 }
206 
207 
208 static void
210 {
211  void *memblock = node->memblock;
212 
213  node->left = node->right = NULL;
214 
215  spinlock_lock(&memtree_lock);
216  if (memleak_tree_root != NULL) {
217  memleak_tree_root = splay(memleak_tree_root, memblock);
218 
219  if (memblock < memleak_tree_root->memblock) {
220  node->left = memleak_tree_root->left;
221  node->right = memleak_tree_root;
222  memleak_tree_root->left = NULL;
223  } else if (memblock > memleak_tree_root->memblock) {
224  node->left = memleak_tree_root;
225  node->right = memleak_tree_root->right;
226  memleak_tree_root->right = NULL;
227  } else {
228  TMSG(MEMLEAK, "memleak splay tree: unable to insert %p (already present)",
229  node->memblock);
230  assert(0);
231  }
232  }
233  memleak_tree_root = node;
234  spinlock_unlock(&memtree_lock);
235 }
236 
237 
238 static struct leakinfo_s *
240 {
241  struct leakinfo_s *result = NULL;
242 
243  spinlock_lock(&memtree_lock);
244  if (memleak_tree_root == NULL) {
245  spinlock_unlock(&memtree_lock);
246  TMSG(MEMLEAK, "memleak splay tree empty: unable to delete %p", memblock);
247  return NULL;
248  }
249 
250  memleak_tree_root = splay(memleak_tree_root, memblock);
251 
252  if (memblock != memleak_tree_root->memblock) {
253  spinlock_unlock(&memtree_lock);
254  TMSG(MEMLEAK, "memleak splay tree: %p not in tree", memblock);
255  return NULL;
256  }
257 
258  result = memleak_tree_root;
259 
260  if (memleak_tree_root->left == NULL) {
261  memleak_tree_root = memleak_tree_root->right;
262  spinlock_unlock(&memtree_lock);
263  return result;
264  }
265 
266  memleak_tree_root->left = splay(memleak_tree_root->left, memblock);
267  memleak_tree_root->left->right = memleak_tree_root->right;
268  memleak_tree_root = memleak_tree_root->left;
269  spinlock_unlock(&memtree_lock);
270  return result;
271 }
272 
273 
274 
275 /******************************************************************************
276  * private operations
277  *****************************************************************************/
278 
279 // Accept 0.ddd as floating point or x/y as fraction.
280 static float
281 string_to_prob(char *str)
282 {
283  int x, y;
284  float ans;
285 
286  if (strchr(str, '/') != NULL) {
287  if (sscanf(str, "%d/%d", &x, &y) == 2 && y > 0) {
288  ans = (float)x / (float)y;
289  } else {
290  ans = DEFAULT_PROB;
291  }
292  } else {
293  if (sscanf(str, "%f", &ans) < 1) {
294  ans = DEFAULT_PROB;
295  }
296  }
297 
298  return ans;
299 }
300 
301 
302 static void
304 {
305  struct timeval tv;
306  char *prob_str;
307  unsigned int seed;
308  int fd;
309 
311  return;
312 
313 #ifdef _SC_PAGESIZE
314  memleak_pagesize = sysconf(_SC_PAGESIZE);
315 #else
317 #endif
318 
319  // If we are sampling the mallocs, then read the probability and
320  // seed the random number generator.
321  prob_str = getenv(HPCRUN_MEMLEAK_PROB);
322  if (prob_str != NULL) {
323  use_memleak_prob = 1;
324  memleak_prob = string_to_prob(prob_str);
325  TMSG(MEMLEAK, "sampling mallocs with prob = %f", memleak_prob);
326 
327  seed = 0;
328  fd = open("/dev/urandom", O_RDONLY);
329  if (fd >= 0) {
330  read(fd, &seed, sizeof(seed));
331  close(fd);
332  }
333  gettimeofday(&tv, NULL);
334  seed += (getpid() << 16) + (tv.tv_usec << 4);
335  srandom(seed);
336  }
337 
338  // unconditionally enable leak detection for now
341 
342  TMSG(MEMLEAK, "init");
343 }
344 
345 
346 // Returns: 1 if p1 and p2 are on the same physical page.
347 //
348 static inline int
349 memleak_same_page(void *p1, void *p2)
350 {
351  uintptr_t n1 = (uintptr_t) p1;
352  uintptr_t n2 = (uintptr_t) p2;
353 
354  return (n1 / memleak_pagesize) == (n2 / memleak_pagesize);
355 }
356 
357 
358 // Choose the location of the leakinfo struct at malloc(). Use a
359 // header if the system and application pointers are on the same page
360 // (so free can look for a header without risking a segfault). Note:
361 // aligned mallocs never get headers.
362 //
363 // sys_ptr = pointer returned by sysem malloc
364 // bytes = size of application's region
365 // align = non-zero if an aligned malloc
366 //
367 // Returns: enum constant for header/footer
368 // appl_ptr = value given to the application
369 // info_ptr = location of the leakinfo struct
370 //
371 static int
372 memleak_get_malloc_loc(void *sys_ptr, size_t bytes, size_t align,
373  void **appl_ptr, leakinfo_t **info_ptr)
374 {
375 #if MEMLEAK_USE_HYBRID_LAYOUT
376  if ( (! ENABLED(MEMLEAK_NO_HEADER)) && align == 0
377  && memleak_same_page(sys_ptr, sys_ptr + leakinfo_size) )
378  {
379  *appl_ptr = sys_ptr + leakinfo_size;
380  *info_ptr = sys_ptr;
381  return MEMLEAK_LOC_HEAD;
382  }
383 #endif
384 
385  // footer
386  *appl_ptr = sys_ptr;
387  *info_ptr = sys_ptr + bytes;
388  return MEMLEAK_LOC_FOOT;
389 }
390 
391 
392 // Find the location of the leakinfo struct at free().
393 //
394 // Returns: enum constant for header/footer/none,
395 // and system and leakinfo pointers.
396 //
397 static int
398 memleak_get_free_loc(void *appl_ptr, void **sys_ptr, leakinfo_t **info_ptr)
399 {
400  static int num_errors = 0;
401 
402 #if MEMLEAK_USE_HYBRID_LAYOUT
403  // try header first
404  *info_ptr = (leakinfo_t *) (appl_ptr - leakinfo_size);
405  if (memleak_same_page(*info_ptr, appl_ptr)
406  && (*info_ptr)->magic == MEMLEAK_MAGIC
407  && (*info_ptr)->memblock == appl_ptr) {
408  *sys_ptr = *info_ptr;
409  return MEMLEAK_LOC_HEAD;
410  }
411 #endif
412 
413  // always try footer
414  *sys_ptr = appl_ptr;
415  *info_ptr = splay_delete(appl_ptr);
416  if (*info_ptr == NULL) {
417  return MEMLEAK_LOC_NONE;
418  }
419  if ((*info_ptr)->magic == MEMLEAK_MAGIC
420  && (*info_ptr)->memblock == appl_ptr) {
421  return MEMLEAK_LOC_FOOT;
422  }
423 
424  // must be memory corruption somewhere. maybe a bug in our code,
425  // but more likely someone else has stomped on our data.
426  num_errors++;
427  if (num_errors < 100) {
428  AMSG("MEMLEAK: Warning: memory corruption in leakinfo node: %p "
429  "sys: %p appl: %p magic: 0x%lx context: %p bytes: %ld memblock: %p",
430  *info_ptr, *sys_ptr, appl_ptr, (*info_ptr)->magic, (*info_ptr)->context,
431  (*info_ptr)->bytes, (*info_ptr)->memblock);
432  }
433  *info_ptr = NULL;
434  return MEMLEAK_LOC_NONE;
435 }
436 
437 
438 // Fill in the leakinfo struct, add metric to CCT, add to splay tree
439 // (if footer) and print TMSG.
440 //
441 static void
442 memleak_add_leakinfo(const char *name, void *sys_ptr, void *appl_ptr,
443  leakinfo_t *info_ptr, size_t bytes, ucontext_t *uc,
444  int loc)
445 {
446  char *loc_str;
447 
448  if (info_ptr == NULL) {
449  TMSG(MEMLEAK, "Warning: %s: bytes: %ld sys: %p appl: %p info: %p "
450  "(NULL leakinfo pointer, this should not happen)",
451  name, bytes, sys_ptr, appl_ptr, info_ptr);
452  return;
453  }
454 
455  info_ptr->magic = MEMLEAK_MAGIC;
456  info_ptr->bytes = bytes;
457  info_ptr->memblock = appl_ptr;
458  info_ptr->left = NULL;
459  info_ptr->right = NULL;
460  if (hpcrun_memleak_active()) {
461  sample_val_t smpl =
463  (hpcrun_metricVal_t) {.i=bytes},
464  0, 1, NULL);
465  info_ptr->context = smpl.sample_node;
466  loc_str = loc_name[loc];
467  } else {
468  info_ptr->context = NULL;
469  loc_str = "inactive";
470  }
471  if (loc == MEMLEAK_LOC_FOOT) {
472  splay_insert(info_ptr);
473  }
474 
475  TMSG(MEMLEAK, "%s: bytes: %ld sys: %p appl: %p info: %p cct: %p (%s)",
476  name, bytes, sys_ptr, appl_ptr, info_ptr, info_ptr->context, loc_str);
477 }
478 
479 
480 // Unified function for all of the mallocs, aligned and unaligned.
481 // Do the malloc, add the leakinfo struct and print TMSG.
482 //
483 // bytes = size of application region
484 // align = size of alignment, or 0 for unaligned
485 // clear = 1 if want region memset to 0 (for calloc)
486 // ret = return value from posix_memalign()
487 //
488 static void *
489 memleak_malloc_helper(const char *name, size_t bytes, size_t align,
490  int clear, ucontext_t *uc, int *ret)
491 {
492  void *sys_ptr, *appl_ptr;
493  leakinfo_t *info_ptr;
494  char *inactive_mesg = "inactive";
495  int active, loc;
496  size_t size;
497 
498  TMSG(MEMLEAK, "%s: bytes: %ld", name, bytes);
499 
500  // do the real malloc, aligned or not. note: we can't track malloc
501  // inside dlopen, that would lead to deadlock.
502  active = 1;
504  active = 0;
505  } else if (TD_GET(inside_dlfcn)) {
506  active = 0;
507  inactive_mesg = "unable to monitor: inside dlfcn";
508  } else if (use_memleak_prob && (random()/(float)RAND_MAX > memleak_prob)) {
509  active = 0;
510  inactive_mesg = "not sampled";
511  }
512  size = bytes + (active ? leakinfo_size : 0);
513  if (align != 0) {
514  // there is no __libc_posix_memalign(), so we use __libc_memalign()
515  // instead, or else use dlsym().
516  sys_ptr = real_memalign(align, size);
517  if (ret != NULL) {
518  *ret = (sys_ptr == NULL) ? errno : 0;
519  }
520  } else {
521  sys_ptr = real_malloc(size);
522  }
523  if (clear && sys_ptr != NULL) {
524  memset(sys_ptr, 0, size);
525  }
526 
527  // inactive or failed malloc
528  if (! active) {
529  TMSG(MEMLEAK, "%s: bytes: %ld, sys: %p (%s)",
530  name, bytes, sys_ptr, inactive_mesg);
531  return sys_ptr;
532  }
533  if (sys_ptr == NULL) {
534  TMSG(MEMLEAK, "%s: bytes: %ld, sys: %p (failed)",
535  name, bytes, sys_ptr);
536  return sys_ptr;
537  }
538 
539  loc = memleak_get_malloc_loc(sys_ptr, bytes, align, &appl_ptr, &info_ptr);
540  memleak_add_leakinfo(name, sys_ptr, appl_ptr, info_ptr, bytes, uc, loc);
541 
542  return appl_ptr;
543 }
544 
545 
546 // Reclaim the data in the leakinfo struct, add metric to CCT,
547 // invalidate the struct and print TMSG.
548 //
549 // sys_ptr = the system malloc pointer
550 // appl_ptr = the application malloc pointer
551 // info_ptr = pointer to our leakinfo struct
552 // loc = enum constant for header/footer/none
553 //
554 static void
555 memleak_free_helper(const char *name, void *sys_ptr, void *appl_ptr,
556  leakinfo_t *info_ptr, int loc)
557 {
558  char *loc_str;
559 
560  if (info_ptr == NULL) {
561  TMSG(MEMLEAK, "%s: sys: %p appl: %p (no malloc)", name, sys_ptr, appl_ptr);
562  return;
563  }
564 
565  if (info_ptr->context != NULL && hpcrun_memleak_active()) {
566  hpcrun_free_inc(info_ptr->context, info_ptr->bytes);
567  loc_str = loc_name[loc];
568  } else {
569  loc_str = "inactive";
570  }
571  info_ptr->magic = 0;
572 
573  TMSG(MEMLEAK, "%s: bytes: %ld sys: %p appl: %p info: %p cct: %p (%s)",
574  name, info_ptr->bytes, sys_ptr, appl_ptr, info_ptr,
575  info_ptr->context, loc_str);
576 }
577 
578 
579 /******************************************************************************
580  * interface operations
581  *****************************************************************************/
582 
583 // The memleak overrides pose extra challenges for safe sampling.
584 // When we enter a memleak override, if we're coming from inside our
585 // own code, we can't just automatically call the real version of the
586 // function and return. The problem is that sometimes we put headers
587 // in front of the malloc'd region and thus the application and the
588 // system don't use the same pointer for the beginning of the region.
589 //
590 // For malloc, memalign, etc, it's ok to return the real version
591 // without a header. The free code checks for the case of no header
592 // or footer. And actually, there are always a few system mallocs
593 // that happen before we get initialized that go untracked.
594 //
595 // But for free, we can't just call the real free if the region might
596 // have a header. In that case, we'd be freeing the wrong pointer and
597 // the memory system would crash.
598 //
599 // Now, we could call the real free if we were 100% certain that the
600 // malloc also came from our code and thus had no header. But if
601 // there's anything that slips through the cracks, then the program
602 // crashes. OTOH, running our code looking for a header might hit
603 // deadlock if the debug MSGS are on. Choose your poison, but
604 // probably this case never happens.
605 //
606 // The moral is: be careful not to use malloc or free in our code.
607 // Use mmap and hpcrun_malloc instead.
608 
609 int
610 MONITOR_EXT_WRAP_NAME(posix_memalign)(void **memptr, size_t alignment,
611  size_t bytes)
612 {
613  ucontext_t uc;
614  int ret = 0;
615 
616  if (! hpcrun_safe_enter()) {
617  *memptr = real_memalign(alignment, bytes);
618  return (*memptr == NULL) ? errno : 0;
619  }
621 
622 #ifdef USE_SYS_GCTXT
623  getcontext(&uc);
624 #else // ! USE_SYS_GCTXT
625  INLINE_ASM_GCTXT(uc);
626 #endif // USE_SYS_GCTXT
627 
628  *memptr = memleak_malloc_helper("posix_memalign", bytes, alignment, 0, &uc, &ret);
630  return ret;
631 }
632 
633 
634 void *
635 MONITOR_EXT_WRAP_NAME(memalign)(size_t boundary, size_t bytes)
636 {
637  ucontext_t uc;
638  void *ptr;
639 
640  if (! hpcrun_safe_enter()) {
641  return real_memalign(boundary, bytes);
642  }
644 
645 #ifdef USE_SYS_GCTXT
646  getcontext(&uc);
647 #else // ! USE_SYS_GCTXT
648  INLINE_ASM_GCTXT(uc);
649 #endif // USE_SYS_GCTXT
650 
651  ptr = memleak_malloc_helper("memalign", bytes, boundary, 0, &uc, NULL);
653  return ptr;
654 }
655 
656 
657 void *
659 {
660  ucontext_t uc;
661  void *ptr;
662 
663  if (! hpcrun_safe_enter()) {
664  return real_valloc(bytes);
665  }
667 
668 #ifdef USE_SYS_GCTXT
669  getcontext(&uc);
670 #else // ! USE_SYS_GCTXT
671  INLINE_ASM_GCTXT(uc);
672 #endif // USE_SYS_GCTXT
673 
674  ptr = memleak_malloc_helper("valloc", bytes, memleak_pagesize, 0, &uc, NULL);
676  return ptr;
677 }
678 
679 
680 void *
682 {
683  ucontext_t uc;
684  void *ptr;
685 
686  if (! hpcrun_safe_enter()) {
687  return real_malloc(bytes);
688  }
690 
691 #ifdef USE_SYS_GCTXT
692  getcontext(&uc);
693 #else // ! USE_SYS_GCTXT
694  INLINE_ASM_GCTXT(uc);
695 #endif // USE_SYS_GCTXT
696 
697  ptr = memleak_malloc_helper("malloc", bytes, 0, 0, &uc, NULL);
699  return ptr;
700 }
701 
702 
703 void *
704 MONITOR_EXT_WRAP_NAME(calloc)(size_t nmemb, size_t bytes)
705 {
706  ucontext_t uc;
707  void *ptr;
708 
709  if (! hpcrun_safe_enter()) {
710  ptr = real_malloc(nmemb * bytes);
711  if (ptr != NULL) {
712  memset(ptr, 0, nmemb * bytes);
713  }
714  return ptr;
715  }
717 
718 #ifdef USE_SYS_GCTXT
719  getcontext(&uc);
720 #else // ! USE_SYS_GCTXT
721  INLINE_ASM_GCTXT(uc);
722 #endif // USE_SYS_GCTXT
723 
724  ptr = memleak_malloc_helper("calloc", nmemb * bytes, 0, 1, &uc, NULL);
726  return ptr;
727 }
728 
729 
730 // For free() and realloc(), we must always look for a header, even if
731 // the metric is inactive and we don't record it in the CCT (unless
732 // memleak is entirely disabled). If the region has a header, then
733 // the system ptr is not the application ptr, and we must find the
734 // sytem ptr or else free() will crash.
735 //
736 void
738 {
739  leakinfo_t *info_ptr;
740  void *sys_ptr;
741  int loc;
742 
743  // look for header, even if came from inside our code.
744  int safe = hpcrun_safe_enter();
745 
747  TMSG(MEMLEAK, "free: ptr: %p", ptr);
748 
749  if (! leak_detection_enabled) {
750  real_free(ptr);
751  TMSG(MEMLEAK, "free: ptr: %p (inactive)", ptr);
752  goto finish;
753  }
754  if (ptr == NULL) {
755  goto finish;
756  }
757 
758  loc = memleak_get_free_loc(ptr, &sys_ptr, &info_ptr);
759  memleak_free_helper("free", sys_ptr, ptr, info_ptr, loc);
760  real_free(sys_ptr);
761 
762 finish:
763  if (safe) {
765  }
766  return;
767 }
768 
769 
770 void *
772 {
773  ucontext_t uc;
774  leakinfo_t *info_ptr;
775  void *ptr2, *appl_ptr, *sys_ptr;
776  char *inactive_mesg = "inactive";
777  int loc, loc2, active;
778 
779  // look for header, even if came from inside our code.
780  int safe = hpcrun_safe_enter();
781 
783  TMSG(MEMLEAK, "realloc: ptr: %p bytes: %ld", ptr, bytes);
784 
785  if (! leak_detection_enabled) {
786  appl_ptr = real_realloc(ptr, bytes);
787  goto finish;
788  }
789 
790 #ifdef USE_SYS_GCTXT
791  getcontext(&uc);
792 #else // ! USE_SYS_GCTXT
793  INLINE_ASM_GCTXT(uc);
794 #endif // USE_SYS_GCTXT
795 
796  // realloc(NULL, bytes) means malloc(bytes)
797  if (ptr == NULL) {
798  appl_ptr = memleak_malloc_helper("realloc/malloc", bytes, 0, 0, &uc, NULL);
799  goto finish;
800  }
801 
802  // for memleak metric, treat realloc as a free of the old bytes
803  loc = memleak_get_free_loc(ptr, &sys_ptr, &info_ptr);
804  memleak_free_helper("realloc/free", sys_ptr, ptr, info_ptr, loc);
805 
806  // realloc(ptr, 0) means free(ptr)
807  if (bytes == 0) {
808  real_free(sys_ptr);
809  appl_ptr = NULL;
810  goto finish;
811  }
812 
813  // if inactive, then do real_realloc() and return.
814  // but if there used to be a header, then must slide user data.
815  // again, can't track malloc inside dlopen.
816  active = 1;
818  active = 0;
819  } else if (TD_GET(inside_dlfcn)) {
820  active = 0;
821  inactive_mesg = "unable to monitor: inside dlfcn";
822  } else if (use_memleak_prob && (random()/(float)RAND_MAX > memleak_prob)) {
823  active = 0;
824  inactive_mesg = "not sampled";
825  }
826  if (! active) {
827  if (loc == MEMLEAK_LOC_HEAD) {
828  // slide left
829  memmove(sys_ptr, ptr, bytes);
830  }
831  appl_ptr = real_realloc(sys_ptr, bytes);
832  TMSG(MEMLEAK, "realloc: bytes: %ld ptr: %p (%s)",
833  bytes, appl_ptr, inactive_mesg);
834  goto finish;
835  }
836 
837  // realloc and add leak info to new location. treat this as a
838  // malloc of the new size. note: if realloc moves the data and
839  // switches header/footer, then need to slide the user data.
840  size_t size = bytes + leakinfo_size;
841  ptr2 = real_realloc(sys_ptr, size);
842  loc2 = memleak_get_malloc_loc(ptr2, bytes, 0, &appl_ptr, &info_ptr);
843  if (loc == MEMLEAK_LOC_HEAD && loc2 != MEMLEAK_LOC_HEAD) {
844  // slide left
845  memmove(ptr2, ptr2 + leakinfo_size, bytes);
846  }
847  else if (loc != MEMLEAK_LOC_HEAD && loc2 == MEMLEAK_LOC_HEAD) {
848  // slide right
849  memmove(ptr2 + leakinfo_size, ptr, bytes);
850  }
851  memleak_add_leakinfo("realloc/malloc", ptr2, appl_ptr, info_ptr, bytes, &uc, loc2);
852 
853 finish:
854  if (safe) {
856  }
857  return appl_ptr;
858 }
static struct leakinfo_s * splay_delete(void *memblock)
void *MONITOR_EXT_WRAP_NAME() realloc(void *ptr, size_t bytes)
int hpcrun_memleak_alloc_id()
Definition: memleak.c:234
cct_node_t * context
static int memleak_get_malloc_loc(void *sys_ptr, size_t bytes, size_t align, void **appl_ptr, leakinfo_t **info_ptr)
int MONITOR_EXT_WRAP_NAME() posix_memalign(void **memptr, size_t alignment, size_t bytes)
static void * memleak_malloc_helper(const char *name, size_t bytes, size_t align, int clear, ucontext_t *uc, int *ret)
#define MEMLEAK_DEFAULT_PAGESIZE
#define real_memalign
static void splay_insert(struct leakinfo_s *node)
void * memalign_fcn(size_t, size_t)
static void hpcrun_safe_exit(void)
#define HPCRUN_MEMLEAK_PROB
sample_val_t hpcrun_sample_callpath(void *context, int metricId, hpcrun_metricVal_t metricIncr, int skipInner, int isSync, sampling_info_t *data)
Definition: sample_event.c:160
static int use_memleak_prob
#define real_malloc
static float string_to_prob(char *str)
#define MONITOR_EXT_WRAP_NAME(name)
Definition: monitor_ext.h:92
static void spinlock_unlock(spinlock_t *l)
Definition: spinlock.h:96
static char * loc_name[4]
cct_node_t * node
Definition: cct.c:128
void * malloc_fcn(size_t)
cct_node_t * sample_node
Definition: sample_event.h:96
#define REGULAR_SPLAY_TREE(type, root, key, value, left, right)
Definition: splay-macros.h:172
static struct leakinfo_s * splay(struct leakinfo_s *root, void *key)
static int memleak_get_free_loc(void *appl_ptr, void **sys_ptr, leakinfo_t **info_ptr)
void free_fcn(void *)
static long memleak_pagesize
static float memleak_prob
int hpcrun_memleak_active()
Definition: memleak.c:241
#define real_realloc
#define MEMLEAK_MAGIC
void *MONITOR_EXT_WRAP_NAME() memalign(size_t boundary, size_t bytes)
static spinlock_t memtree_lock
void * valloc_fcn(size_t)
void *MONITOR_EXT_WRAP_NAME() calloc(size_t nmemb, size_t bytes)
void *MONITOR_EXT_WRAP_NAME() valloc(size_t bytes)
struct leakinfo_s leakinfo_t
static int num_errors
#define TD_GET(field)
Definition: thread_data.h:256
static void spinlock_lock(spinlock_t *l)
Definition: spinlock.h:111
#define TMSG(f,...)
Definition: messages.h:93
struct leakinfo_s * left
#define DEFAULT_PROB
void hpcrun_free_inc(cct_node_t *node, int incr)
Definition: memleak.c:268
#define AMSG
Definition: messages.h:71
ssize_t MONITOR_EXT_WRAP_NAME() read(int fd, void *buf, size_t count)
Definition: io-over.c:152
#define NULL
Definition: ElfHelper.cpp:85
#define real_valloc
static int leak_detection_init
static int memleak_same_page(void *p1, void *p2)
unsigned char uc
Definition: amd-xop.c:3
static int leakinfo_size
Definition: cct.c:96
void MONITOR_EXT_WRAP_NAME() free(void *ptr)
static void memleak_add_leakinfo(const char *name, void *sys_ptr, void *appl_ptr, leakinfo_t *info_ptr, size_t bytes, ucontext_t *uc, int loc)
static struct leakinfo_s * memleak_tree_root
static void memleak_initialize(void)
static int leak_detection_enabled
void * realloc_fcn(void *, size_t)
#define real_free
struct leakinfo_s * right
#define SPINLOCK_UNLOCKED
Definition: spinlock.h:84
void *MONITOR_EXT_WRAP_NAME() malloc(size_t bytes)
static int hpcrun_safe_enter(void)
static void memleak_free_helper(const char *name, void *sys_ptr, void *appl_ptr, leakinfo_t *info_ptr, int loc)
#define INLINE_ASM_GCTXT(uc)
leakinfo_t leakinfo_NULL
#define ENABLED(f)
Definition: debug-flag.h:76