Hide __posix_spawn_file_actions_realloc/__spawni [BZ #18822]
[glibc.git] / malloc / mtrace.c
blob9eb2f5f1c7b3196afdaa18a01b0da198689ee102
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2017 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 <http://www.gnu.org/licenses/>. */
21 #ifndef _MALLOC_INTERNAL
22 # define _MALLOC_INTERNAL
23 # include <malloc.h>
24 # include <mcheck.h>
25 # include <libc-lock.h>
26 #endif
28 #include <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
34 #include <_itoa.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... */
54 void *mallwatch;
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,
60 const void *);
61 static void *(*tr_old_memalign_hook) (size_t __alignment, size_t __size,
62 const void *);
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
67 tr_break. */
69 extern void tr_break (void) __THROW;
70 libc_hidden_proto (tr_break)
71 void
72 tr_break (void)
75 libc_hidden_def (tr_break)
77 static void
78 tr_where (const void *caller, Dl_info *info)
80 if (caller != NULL)
82 if (info != NULL)
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 *));
90 buf[0] = '(';
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,
95 len),
96 caller >= (void *) info->dli_saddr
97 ? "+0x" : "-0x"),
98 16, 0),
99 ")");
102 fprintf (mallstream, "@ %s%s%s[%p] ",
103 info->dli_fname ? : "", info->dli_fname ? ":" : "",
104 buf, caller);
106 else
107 fprintf (mallstream, "@ [%p] ", caller);
111 static Dl_info *
112 lock_and_info (const void *caller, Dl_info *mem)
114 if (caller == NULL)
115 return NULL;
117 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
119 __libc_lock_lock (lock);
121 return res;
124 static void
125 tr_freehook (void *ptr, const void *caller)
127 if (ptr == NULL)
128 return;
130 Dl_info mem;
131 Dl_info *info = lock_and_info (caller, &mem);
132 tr_where (caller, info);
133 /* Be sure to print it first. */
134 fprintf (mallstream, "- %p\n", ptr);
135 if (ptr == mallwatch)
137 __libc_lock_unlock (lock);
138 tr_break ();
139 __libc_lock_lock (lock);
141 __free_hook = tr_old_free_hook;
142 if (tr_old_free_hook != NULL)
143 (*tr_old_free_hook)(ptr, caller);
144 else
145 free (ptr);
146 __free_hook = tr_freehook;
147 __libc_lock_unlock (lock);
150 static void *
151 tr_mallochook (size_t size, const void *caller)
153 void *hdr;
155 Dl_info mem;
156 Dl_info *info = lock_and_info (caller, &mem);
158 __malloc_hook = tr_old_malloc_hook;
159 if (tr_old_malloc_hook != NULL)
160 hdr = (void *) (*tr_old_malloc_hook)(size, caller);
161 else
162 hdr = (void *) malloc (size);
163 __malloc_hook = tr_mallochook;
165 tr_where (caller, info);
166 /* We could be printing a NULL here; that's OK. */
167 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
169 __libc_lock_unlock (lock);
171 if (hdr == mallwatch)
172 tr_break ();
174 return hdr;
177 static void *
178 tr_reallochook (void *ptr, size_t size, const void *caller)
180 void *hdr;
182 if (ptr == mallwatch)
183 tr_break ();
185 Dl_info mem;
186 Dl_info *info = lock_and_info (caller, &mem);
188 __free_hook = tr_old_free_hook;
189 __malloc_hook = tr_old_malloc_hook;
190 __realloc_hook = tr_old_realloc_hook;
191 if (tr_old_realloc_hook != NULL)
192 hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
193 else
194 hdr = (void *) realloc (ptr, size);
195 __free_hook = tr_freehook;
196 __malloc_hook = tr_mallochook;
197 __realloc_hook = tr_reallochook;
199 tr_where (caller, info);
200 if (hdr == NULL)
202 if (size != 0)
203 /* Failed realloc. */
204 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
205 else
206 fprintf (mallstream, "- %p\n", ptr);
208 else if (ptr == NULL)
209 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
210 else
212 fprintf (mallstream, "< %p\n", ptr);
213 tr_where (caller, info);
214 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
217 __libc_lock_unlock (lock);
219 if (hdr == mallwatch)
220 tr_break ();
222 return hdr;
225 static void *
226 tr_memalignhook (size_t alignment, size_t size, const void *caller)
228 void *hdr;
230 Dl_info mem;
231 Dl_info *info = lock_and_info (caller, &mem);
233 __memalign_hook = tr_old_memalign_hook;
234 __malloc_hook = tr_old_malloc_hook;
235 if (tr_old_memalign_hook != NULL)
236 hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
237 else
238 hdr = (void *) memalign (alignment, size);
239 __memalign_hook = tr_memalignhook;
240 __malloc_hook = tr_mallochook;
242 tr_where (caller, info);
243 /* We could be printing a NULL here; that's OK. */
244 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
246 __libc_lock_unlock (lock);
248 if (hdr == mallwatch)
249 tr_break ();
251 return hdr;
255 #ifdef _LIBC
257 /* This function gets called to make sure all memory the library
258 allocates get freed and so does not irritate the user when studying
259 the mtrace output. */
260 static void __libc_freeres_fn_section
261 release_libc_mem (void)
263 /* Only call the free function if we still are running in mtrace mode. */
264 if (mallstream != NULL)
265 __libc_freeres ();
267 #endif
270 /* We enable tracing if either the environment variable MALLOC_TRACE
271 is set, or if the variable mallwatch has been patched to an address
272 that the debugging user wants us to stop on. When patching mallwatch,
273 don't forget to set a breakpoint on tr_break! */
275 void
276 mtrace (void)
278 #ifdef _LIBC
279 static int added_atexit_handler;
280 #endif
281 char *mallfile;
283 /* Don't panic if we're called more than once. */
284 if (mallstream != NULL)
285 return;
287 #ifdef _LIBC
288 /* When compiling the GNU libc we use the secure getenv function
289 which prevents the misuse in case of SUID or SGID enabled
290 programs. */
291 mallfile = __libc_secure_getenv (mallenv);
292 #else
293 mallfile = getenv (mallenv);
294 #endif
295 if (mallfile != NULL || mallwatch != NULL)
297 char *mtb = malloc (TRACE_BUFFER_SIZE);
298 if (mtb == NULL)
299 return;
301 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
302 if (mallstream != NULL)
304 /* Be sure it doesn't malloc its buffer! */
305 malloc_trace_buffer = mtb;
306 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
307 fprintf (mallstream, "= Start\n");
308 tr_old_free_hook = __free_hook;
309 __free_hook = tr_freehook;
310 tr_old_malloc_hook = __malloc_hook;
311 __malloc_hook = tr_mallochook;
312 tr_old_realloc_hook = __realloc_hook;
313 __realloc_hook = tr_reallochook;
314 tr_old_memalign_hook = __memalign_hook;
315 __memalign_hook = tr_memalignhook;
316 #ifdef _LIBC
317 if (!added_atexit_handler)
319 added_atexit_handler = 1;
320 __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
321 __dso_handle);
323 #endif
325 else
326 free (mtb);
330 void
331 muntrace (void)
333 if (mallstream == NULL)
334 return;
336 /* Do the reverse of what done in mtrace: first reset the hooks and
337 MALLSTREAM, and only after that write the trailer and close the
338 file. */
339 FILE *f = mallstream;
340 mallstream = NULL;
341 __free_hook = tr_old_free_hook;
342 __malloc_hook = tr_old_malloc_hook;
343 __realloc_hook = tr_old_realloc_hook;
344 __memalign_hook = tr_old_memalign_hook;
346 fprintf (f, "= End\n");
347 fclose (f);