1 /* This file is part of XEmacs.
3 XEmacs is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2, or (at your option) any
8 XEmacs is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 You should have received a copy of the GNU General Public License
14 along with XEmacs; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA. */
18 /* Synched up with: Not in FSF. */
20 /* Debugging hooks for malloc. */
22 /* These hooks work with gmalloc to catch allocation errors.
23 In particular, the following is trapped:
25 * Freeing the same pointer twice.
26 * Trying to free a pointer not returned by malloc.
27 * Trying to realloc a pointer not returned by malloc.
29 In addition, every word of every block freed is set to
30 0xdeadbeef. This causes many uses of freed storage to be
31 trapped or recognized.
33 When you use this, the storage used by the last FREE_QUEUE_LIMIT
34 calls to free() is not recycled. When you call free for the Nth
35 time, the (N - FREE_QUEUE_LIMIT)'th block is actually recycled.
37 For these last FREE_QUEUE_LIMIT calls to free() a backtrace is
38 saved showing where it was called from. The function
39 find_backtrace() is provided here to be called from GDB with a
40 pointer (such as would be passed to free()) as argument, e.g.
41 (gdb) p/a *find_backtrace (0x234000). If SAVE_ARGS is defined,
42 the first three arguments to each function are saved as well as the
45 If UNMAPPED_FREE is defined, instead of setting every word of freed
46 storage to 0xdeadbeef, every call to malloc goes on its own page(s).
47 When free() is called, the block is read and write protected. This
48 is very useful when debugging, since it usually generates a bus error
49 when the deadbeef hack might only cause some garbage to be printed.
50 However, this is too slow for everyday use, since it takes an enormous
54 Some other features that would be useful are:
56 * Checking for storage leaks.
57 This could be done by a GC-like facility that would scan the data
58 segment looking for pointers to allocated storage and tell you
59 about those that are no longer referenced. This could be invoked
60 at any time. Another possibility is to report on what allocated
61 storage is still in use when the process is exited. Typically
62 there will be a large amount, so this might not be very useful.
65 #if defined (EMACS_BTL) && defined (sun4) && !defined (__lucid)
66 /* currently only works in this configuration */
72 #include "cadillac-btl.h"
77 void *malloc (unsigned long);
80 #if !defined(HAVE_LIBMCHECK)
87 #include <sys/param.h>
88 #define ROUND_UP_TO_PAGE(i) (((i) + PAGEOFFSET) & PAGEMASK)
91 #include <sys/types.h>
93 /* System function prototypes don't belong in C source files */
94 /* extern void free (void *); */
96 c_hashtable pointer_table;
98 extern void (*__free_hook) (void *);
99 extern void *(*__malloc_hook) (unsigned long);
101 static void *check_malloc (unsigned long);
103 typedef void (*fun_ptr) ();
106 #define FREE_QUEUE_LIMIT 1000
108 /* free_queue is not too useful without backtrace logging */
109 #define FREE_QUEUE_LIMIT 1
111 #define TRACE_LIMIT 20
122 unsigned long length;
124 fun_entry backtrace[TRACE_LIMIT];
128 free_queue_entry free_queue[FREE_QUEUE_LIMIT];
134 init_frame (FRAME *fptr)
139 /* Do the system trap ST_FLUSH_WINDOWS */
141 asm ("st %sp, [%i0+0]");
142 asm ("st %fp, [%i0+4]");
145 fptr->pc = (char *) init_frame;
148 PREVIOUS_FRAME (tmp_frame);
156 frame_arg (FRAME *fptr, int index)
158 return ((void *) FRAME_ARG(*fptr, index));
163 save_backtrace (FRAME *current_frame_ptr, fun_entry *table)
169 FRAME current_frame = *current_frame_ptr;
171 /* Get up and out of free() */
172 PREVIOUS_FRAME (current_frame);
174 /* now do the basic loop adding data until there is no more */
175 while (PREVIOUS_FRAME (current_frame) && i < TRACE_LIMIT)
177 table[i].return_pc = (void (*)())FRAME_PC (current_frame);
179 for (j = 0; j < 3; j++)
180 table[i].arg[j] = frame_arg (¤t_frame, j);
184 memset (&table[i], 0, sizeof (fun_entry) * (TRACE_LIMIT - i));
188 find_backtrace (void *ptr)
192 for (i = 0; i < FREE_QUEUE_LIMIT; i++)
193 if (free_queue[i].address == ptr)
194 return &free_queue[i];
198 #endif /* SAVE_STACK */
200 int strict_free_check;
203 check_free (void *ptr)
208 init_frame (&start_frame);
214 pointer_table = make_hashtable (max (100, FREE_QUEUE_LIMIT * 2));
219 unsigned long rounded_up_size;
222 EMACS_INT present = (EMACS_INT) gethash (ptr, pointer_table,
223 (CONST void **) &size);
227 /* This can only happen if you try to free something that didn't
229 #if !defined(__linux__)
230 /* I originally wrote: "There's really no need to drop core."
231 I have seen the error of my ways. -slb */
232 if (strict_free_check)
235 printf("Freeing unmalloc'ed memory at %p\n", ptr);
236 __free_hook = check_free;
237 __malloc_hook = check_malloc;
243 /* This happens when you free twice */
244 #if !defined(__linux__)
245 /* See above comment. */
246 if (strict_free_check)
249 printf("Freeing %p twice\n", ptr);
250 __free_hook = check_free;
251 __malloc_hook = check_malloc;
255 puthash (ptr, (void *)-size, pointer_table);
257 /* Round up size to an even number of pages. */
258 rounded_up_size = ROUND_UP_TO_PAGE (size);
259 /* Protect the pages freed from all access */
260 if (strict_free_check)
261 mprotect (ptr, rounded_up_size, PROT_NONE);
263 /* Set every word in the block to 0xdeadbeef */
264 if (strict_free_check)
266 unsigned long long_length = (size + (sizeof (long) - 1))
270 for (i = 0; i < long_length; i++)
271 ((unsigned long *) ptr)[i] = 0xdeadbeef;
274 free_queue[current_free].address = ptr;
275 free_queue[current_free].length = size;
277 save_backtrace (&start_frame,
278 free_queue[current_free].backtrace);
281 if (current_free >= FREE_QUEUE_LIMIT)
283 /* Really free this if there's something there */
285 void *old = free_queue[current_free].address;
290 unsigned long old_len = free_queue[current_free].length;
292 mprotect (old, old_len, PROT_READ | PROT_WRITE | PROT_EXEC);
295 remhash (old, pointer_table);
299 __free_hook = check_free;
300 __malloc_hook = check_malloc;
307 check_malloc (unsigned long size)
309 unsigned long rounded_up_size;
320 /* Round up to an even number of pages. */
321 rounded_up_size = ROUND_UP_TO_PAGE (size);
323 rounded_up_size = size;
325 result = malloc (rounded_up_size);
327 pointer_table = make_hashtable (FREE_QUEUE_LIMIT * 2);
328 puthash (result, (void *)size, pointer_table);
329 __free_hook = check_free;
330 __malloc_hook = check_malloc;
335 extern void *(*__realloc_hook) (void *, unsigned long);
340 #define MIN(A, B) ((A) < (B) ? (A) : (B))
342 /* Don't optimize realloc */
345 check_realloc (void * ptr, unsigned long size)
348 unsigned long old_size;
349 void *result = malloc (size);
351 if (!ptr) return result;
352 present = (EMACS_INT) gethash (ptr, pointer_table, (CONST void **) &old_size);
355 /* This can only happen by reallocing a pointer that didn't
357 #if !defined(__linux__)
358 /* see comment in check_free(). */
361 printf("Realloc'ing unmalloc'ed pointer at %p\n", ptr);
366 memcpy (result, ptr, MIN (size, old_size));
372 void enable_strict_free_check (void);
374 enable_strict_free_check (void)
376 strict_free_check = 1;
379 void disable_strict_free_check (void);
381 disable_strict_free_check (void)
383 strict_free_check = 0;
386 /* Note: All BLOCK_INPUT stuff removed from this file because it's
387 completely gone in XEmacs */
390 block_input_malloc (unsigned long size);
393 block_input_free (void* ptr)
398 __free_hook = block_input_free;
399 __malloc_hook = block_input_malloc;
403 block_input_malloc (unsigned long size)
408 result = malloc (size);
409 __free_hook = block_input_free;
410 __malloc_hook = block_input_malloc;
416 block_input_realloc (void* ptr, unsigned long size)
422 result = realloc (ptr, size);
423 __free_hook = block_input_free;
424 __malloc_hook = block_input_malloc;
425 __realloc_hook = block_input_realloc;
431 void disable_free_hook (void);
433 disable_free_hook (void)
435 __free_hook = block_input_free;
436 __malloc_hook = block_input_malloc;
437 __realloc_hook = block_input_realloc;
441 init_free_hook (void)
443 __free_hook = check_free;
444 __malloc_hook = check_malloc;
445 __realloc_hook = check_realloc;
447 strict_free_check = 1;
450 void really_free_one_entry (void *, int, int *);
452 DEFUN ("really-free", Freally_free, 0, 1, "P", /*
453 Actually free the storage held by the free() debug hook.
454 A no-op if the free hook is disabled.
459 Lisp_Object lisp_count[2];
461 if ((__free_hook != 0) && pointer_table)
466 maphash ((maphash_function)really_free_one_entry,
467 pointer_table, (void *)&count);
468 memset (free_queue, 0, sizeof (free_queue_entry) * FREE_QUEUE_LIMIT);
470 __free_hook = check_free;
471 XSETINT (lisp_count[0], count[0]);
472 XSETINT (lisp_count[1], count[1]);
473 return Fcons (lisp_count[0], lisp_count[1]);
476 return Fcons (make_int (0), make_int (0));
480 really_free_one_entry (void *key, int contents, int *countp)
486 mprotect (key, -contents, PROT_READ | PROT_WRITE | PROT_EXEC);
488 remhash (key, pointer_table);
490 countp[1] += -contents;
495 syms_of_free_hook (void)
497 DEFSUBR (Freally_free);
501 void (*__free_hook)() = check_free;
502 void *(*__malloc_hook)() = check_malloc;
503 void *(*__realloc_hook)() = check_realloc;
506 #endif /* !defined(HAVE_LIBMCHECK) */
508 #if defined(DEBUG_INPUT_BLOCKING) || defined (DEBUG_GCPRO)
510 /* Note: There is no more input blocking in XEmacs */
512 block_type, unblock_type, totally_type,
513 gcpro1_type, gcpro2_type, gcpro3_type, gcpro4_type, ungcpro_type
516 struct block_input_history_struct
523 fun_entry backtrace[TRACE_LIMIT];
527 typedef struct block_input_history_struct block_input_history;
531 #ifdef DEBUG_INPUT_BLOCKING
535 #define BLHISTLIMIT 1000
537 block_input_history blhist[BLHISTLIMIT];
539 note_block_input (char *file, int line)
541 note_block (file, line, block_type);
542 if (interrupt_input_blocked > 2) abort();
545 note_unblock_input (char* file, int line)
547 note_block (file, line, unblock_type);
550 note_totally_unblocked (char* file, int line)
552 note_block (file, line, totally_type);
555 note_block (char *file, int line, blocktype type)
560 init_frame (&start_frame);
563 blhist[blhistptr].file = file;
564 blhist[blhistptr].line = line;
565 blhist[blhistptr].type = type;
566 blhist[blhistptr].value = interrupt_input_blocked;
569 save_backtrace (&start_frame,
570 blhist[blhistptr].backtrace);
574 if (blhistptr >= BLHISTLIMIT)
584 #define GCPROHISTLIMIT 1000
585 block_input_history gcprohist[GCPROHISTLIMIT];
588 log_gcpro (char *file, int line, struct gcpro *value, blocktype type)
592 if (type == ungcpro_type)
594 if (value == gcprolist) goto OK;
595 if (! gcprolist) abort ();
596 if (value == gcprolist->next) goto OK;
597 if (! gcprolist->next) abort ();
598 if (value == gcprolist->next->next) goto OK;
599 if (! gcprolist->next->next) abort ();
600 if (value == gcprolist->next->next->next) goto OK;
605 init_frame (&start_frame);
607 gcprohist[gcprohistptr].file = file;
608 gcprohist[gcprohistptr].line = line;
609 gcprohist[gcprohistptr].type = type;
610 gcprohist[gcprohistptr].value = (int) value;
612 save_backtrace (&start_frame, gcprohist[gcprohistptr].backtrace);
615 if (gcprohistptr >= GCPROHISTLIMIT)
620 debug_gcpro1 (char *file, int line, struct gcpro *gcpro1, Lisp_Object *var)
622 gcpro1->next = gcprolist; gcpro1->var = var; gcpro1->nvars = 1;
624 log_gcpro (file, line, gcpro1, gcpro1_type);
628 debug_gcpro2 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
629 Lisp_Object *var1, Lisp_Object *var2)
631 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
632 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
634 log_gcpro (file, line, gcpro2, gcpro2_type);
638 debug_gcpro3 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
639 struct gcpro *gcpro3, Lisp_Object *var1, Lisp_Object *var2,
642 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
643 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
644 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
646 log_gcpro (file, line, gcpro3, gcpro3_type);
650 debug_gcpro4 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
651 struct gcpro *gcpro3, struct gcpro *gcpro4, Lisp_Object *var1,
652 Lisp_Object *var2, Lisp_Object *var3, Lisp_Object *var4)
654 log_gcpro (file, line, gcpro4, gcpro4_type);
655 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
656 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
657 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
658 gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
663 debug_gcpro5 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
664 struct gcpro *gcpro3, struct gcpro *gcpro4, struct gcpro *gcpro5,
665 Lisp_Object *var1, Lisp_Object *var2, Lisp_Object *var3,
666 Lisp_Object *var4, Lisp_Object *var5)
668 log_gcpro (file, line, gcpro5, gcpro5_type);
669 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
670 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
671 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
672 gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
673 gcpro5->next = gcpro4; gcpro5->var = var5; gcpro5->nvars = 1;
678 debug_ungcpro (char *file, int line, struct gcpro *gcpro1)
680 log_gcpro (file, line, gcpro1, ungcpro_type);
681 gcprolist = gcpro1->next;
685 show_gcprohist (void)
688 for (i = 0, j = gcprohistptr;
692 if (j >= GCPROHISTLIMIT)
694 printf ("%3d %s %d %s 0x%x\n",
695 j, gcprohist[j].file, gcprohist[j].line,
696 (gcprohist[j].type == gcpro1_type ? "GCPRO1" :
697 gcprohist[j].type == gcpro2_type ? "GCPRO2" :
698 gcprohist[j].type == gcpro3_type ? "GCPRO3" :
699 gcprohist[j].type == gcpro4_type ? "GCPRO4" :
700 gcprohist[j].type == ungcpro_type ? "UNGCPRO" : "???"),