1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Written April 2, 1991 by John Gilmore of Cygnus Support.
5 Based on mcheck.c by Mike Haertel.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <https://www.gnu.org/licenses/>. */
21 #ifndef _MALLOC_INTERNAL
22 # define _MALLOC_INTERNAL
25 # include <libc-lock.h>
36 #include <libc-internal.h>
37 #include <dso_handle.h>
39 #include <libio/iolibio.h>
40 #define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
41 #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
43 #include <kernel-features.h>
45 #define TRACE_BUFFER_SIZE 512
47 static FILE *mallstream
;
48 static const char mallenv
[] = "MALLOC_TRACE";
49 static char *malloc_trace_buffer
;
51 __libc_lock_define_initialized (static, lock
);
53 /* Address to breakpoint on accesses to... */
56 /* Old hook values. */
57 static void (*tr_old_free_hook
) (void *ptr
, const void *);
58 static void *(*tr_old_malloc_hook
) (size_t size
, const void *);
59 static void *(*tr_old_realloc_hook
) (void *ptr
, size_t size
,
61 static void *(*tr_old_memalign_hook
) (size_t __alignment
, size_t __size
,
64 /* This function is called when the block being alloc'd, realloc'd, or
65 freed has an address matching the variable "mallwatch". In a debugger,
66 set "mallwatch" to the address of interest, then put a breakpoint on
69 extern void tr_break (void) __THROW
;
70 libc_hidden_proto (tr_break
)
75 libc_hidden_def (tr_break
)
78 tr_where (const void *caller
, Dl_info
*info
)
84 char *buf
= (char *) "";
85 if (info
->dli_sname
!= NULL
)
87 size_t len
= strlen (info
->dli_sname
);
88 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
91 __stpcpy (_fitoa (caller
>= (const void *) info
->dli_saddr
92 ? caller
- (const void *) info
->dli_saddr
93 : (const void *) info
->dli_saddr
- caller
,
94 __stpcpy (__mempcpy (buf
+ 1, info
->dli_sname
,
96 caller
>= (void *) info
->dli_saddr
102 fprintf (mallstream
, "@ %s%s%s[%p] ",
103 info
->dli_fname
? : "", info
->dli_fname
? ":" : "",
107 fprintf (mallstream
, "@ [%p] ", caller
);
112 lock_and_info (const void *caller
, Dl_info
*mem
)
117 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
119 __libc_lock_lock (lock
);
124 static void tr_freehook (void *, const void *);
125 static void * tr_mallochook (size_t, const void *);
126 static void * tr_reallochook (void *, size_t, const void *);
127 static void * tr_memalignhook (size_t, size_t, const void *);
129 /* Set all the default non-trace hooks. */
130 static __always_inline
void
131 set_default_hooks (void)
133 __free_hook
= tr_old_free_hook
;
134 __malloc_hook
= tr_old_malloc_hook
;
135 __realloc_hook
= tr_old_realloc_hook
;
136 __memalign_hook
= tr_old_memalign_hook
;
139 /* Set all of the tracing hooks used for mtrace. */
140 static __always_inline
void
141 set_trace_hooks (void)
143 __free_hook
= tr_freehook
;
144 __malloc_hook
= tr_mallochook
;
145 __realloc_hook
= tr_reallochook
;
146 __memalign_hook
= tr_memalignhook
;
149 /* Save the current set of hooks as the default hooks. */
150 static __always_inline
void
151 save_default_hooks (void)
153 tr_old_free_hook
= __free_hook
;
154 tr_old_malloc_hook
= __malloc_hook
;
155 tr_old_realloc_hook
= __realloc_hook
;
156 tr_old_memalign_hook
= __memalign_hook
;
160 tr_freehook (void *ptr
, const void *caller
)
166 Dl_info
*info
= lock_and_info (caller
, &mem
);
167 tr_where (caller
, info
);
168 /* Be sure to print it first. */
169 fprintf (mallstream
, "- %p\n", ptr
);
170 if (ptr
== mallwatch
)
172 __libc_lock_unlock (lock
);
174 __libc_lock_lock (lock
);
176 set_default_hooks ();
177 if (tr_old_free_hook
!= NULL
)
178 (*tr_old_free_hook
)(ptr
, caller
);
182 __libc_lock_unlock (lock
);
186 tr_mallochook (size_t size
, const void *caller
)
191 Dl_info
*info
= lock_and_info (caller
, &mem
);
193 set_default_hooks ();
194 if (tr_old_malloc_hook
!= NULL
)
195 hdr
= (void *) (*tr_old_malloc_hook
)(size
, caller
);
197 hdr
= (void *) malloc (size
);
200 tr_where (caller
, info
);
201 /* We could be printing a NULL here; that's OK. */
202 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
204 __libc_lock_unlock (lock
);
206 if (hdr
== mallwatch
)
213 tr_reallochook (void *ptr
, size_t size
, const void *caller
)
217 if (ptr
== mallwatch
)
221 Dl_info
*info
= lock_and_info (caller
, &mem
);
223 set_default_hooks ();
224 if (tr_old_realloc_hook
!= NULL
)
225 hdr
= (void *) (*tr_old_realloc_hook
)(ptr
, size
, caller
);
227 hdr
= (void *) realloc (ptr
, size
);
230 tr_where (caller
, info
);
234 /* Failed realloc. */
235 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
237 fprintf (mallstream
, "- %p\n", ptr
);
239 else if (ptr
== NULL
)
240 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
243 fprintf (mallstream
, "< %p\n", ptr
);
244 tr_where (caller
, info
);
245 fprintf (mallstream
, "> %p %#lx\n", hdr
, (unsigned long int) size
);
248 __libc_lock_unlock (lock
);
250 if (hdr
== mallwatch
)
257 tr_memalignhook (size_t alignment
, size_t size
, const void *caller
)
262 Dl_info
*info
= lock_and_info (caller
, &mem
);
264 set_default_hooks ();
265 if (tr_old_memalign_hook
!= NULL
)
266 hdr
= (void *) (*tr_old_memalign_hook
)(alignment
, size
, caller
);
268 hdr
= (void *) memalign (alignment
, size
);
271 tr_where (caller
, info
);
272 /* We could be printing a NULL here; that's OK. */
273 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
275 __libc_lock_unlock (lock
);
277 if (hdr
== mallwatch
)
286 /* This function gets called to make sure all memory the library
287 allocates get freed and so does not irritate the user when studying
288 the mtrace output. */
289 static void __libc_freeres_fn_section
290 release_libc_mem (void)
292 /* Only call the free function if we still are running in mtrace mode. */
293 if (mallstream
!= NULL
)
299 /* We enable tracing if either the environment variable MALLOC_TRACE
300 is set, or if the variable mallwatch has been patched to an address
301 that the debugging user wants us to stop on. When patching mallwatch,
302 don't forget to set a breakpoint on tr_break! */
308 static int added_atexit_handler
;
312 /* Don't panic if we're called more than once. */
313 if (mallstream
!= NULL
)
317 /* When compiling the GNU libc we use the secure getenv function
318 which prevents the misuse in case of SUID or SGID enabled
320 mallfile
= __libc_secure_getenv (mallenv
);
322 mallfile
= getenv (mallenv
);
324 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
326 char *mtb
= malloc (TRACE_BUFFER_SIZE
);
330 mallstream
= fopen (mallfile
!= NULL
? mallfile
: "/dev/null", "wce");
331 if (mallstream
!= NULL
)
333 /* Be sure it doesn't malloc its buffer! */
334 malloc_trace_buffer
= mtb
;
335 setvbuf (mallstream
, malloc_trace_buffer
, _IOFBF
, TRACE_BUFFER_SIZE
);
336 fprintf (mallstream
, "= Start\n");
337 save_default_hooks ();
340 if (!added_atexit_handler
)
342 added_atexit_handler
= 1;
343 __cxa_atexit ((void (*)(void *))release_libc_mem
, NULL
,
356 if (mallstream
== NULL
)
359 /* Do the reverse of what done in mtrace: first reset the hooks and
360 MALLSTREAM, and only after that write the trailer and close the
362 FILE *f
= mallstream
;
364 set_default_hooks ();
366 fprintf (f
, "= End\n");