XEmacs 21.2-b1
[chise/xemacs-chise.git.1] / src / free-hook.c
1 /* This file is part of XEmacs.
2
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
6 later version.
7
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
11 for more details.
12
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.  */
17
18 /* Synched up with: Not in FSF. */
19
20 /* Debugging hooks for malloc. */
21
22 /* These hooks work with gmalloc to catch allocation errors.
23    In particular, the following is trapped:
24
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.
28
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.
32
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.
36
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
43    return addresses.
44
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
51    number of pages.
52
53
54    Some other features that would be useful are:
55
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.
63 */
64
65 #if defined (EMACS_BTL) && defined (sun4) && !defined (__lucid)
66 /* currently only works in this configuration */
67 # define SAVE_STACK
68 #endif
69
70 #ifdef emacs
71 #ifdef SAVE_STACK
72 #include "cadillac-btl.h"
73 #endif
74 #include <config.h>
75 #include "lisp.h"
76 #else
77 void *malloc (unsigned long);
78 #endif
79
80 #if !defined(HAVE_LIBMCHECK)
81 #include <stdio.h>
82
83 #include "hash.h"
84
85 #ifdef UNMAPPED_FREE
86 #include <sys/mman.h>
87 #include <sys/param.h>
88 #define ROUND_UP_TO_PAGE(i) (((i) + PAGEOFFSET) & PAGEMASK)
89 #endif
90
91 #include <sys/types.h>
92
93 /* System function prototypes don't belong in C source files */
94 /* extern void free (void *); */
95
96 c_hashtable pointer_table;
97
98 extern void (*__free_hook) (void *);
99 extern void *(*__malloc_hook) (unsigned long);
100
101 static void *check_malloc (unsigned long);
102
103 typedef void (*fun_ptr) ();
104
105 #ifdef SAVE_STACK
106 #define FREE_QUEUE_LIMIT 1000
107 #else
108 /* free_queue is not too useful without backtrace logging */
109 #define FREE_QUEUE_LIMIT 1
110 #endif
111 #define TRACE_LIMIT 20
112
113 typedef struct {
114   fun_ptr return_pc;
115 #ifdef SAVE_ARGS
116   void *arg[3];
117 #endif
118 } fun_entry;
119
120 typedef struct {
121   void *address;
122   unsigned long length;
123 #ifdef SAVE_STACK
124   fun_entry backtrace[TRACE_LIMIT];
125 #endif
126 } free_queue_entry;
127
128 free_queue_entry free_queue[FREE_QUEUE_LIMIT];
129
130 int current_free;
131
132 #ifdef SAVE_STACK
133 static void
134 init_frame (FRAME *fptr)
135 {
136   FRAME tmp_frame;
137
138 #ifdef sparc
139   /* Do the system trap ST_FLUSH_WINDOWS */
140   asm ("ta 3");
141   asm ("st %sp, [%i0+0]");
142   asm ("st %fp, [%i0+4]");
143 #endif
144
145   fptr->pc = (char *) init_frame;
146   tmp_frame = *fptr;
147
148   PREVIOUS_FRAME (tmp_frame);
149
150   *fptr = tmp_frame;
151   return;
152 }
153
154 #ifdef SAVE_ARGS
155 static void *
156 frame_arg (FRAME *fptr, int index)
157 {
158   return ((void *) FRAME_ARG(*fptr, index));
159 }
160 #endif
161
162 static void
163 save_backtrace (FRAME *current_frame_ptr, fun_entry *table)
164 {
165   int i = 0;
166 #ifdef SAVE_ARGS
167   int j;
168 #endif
169   FRAME current_frame = *current_frame_ptr;
170
171   /* Get up and out of free() */
172   PREVIOUS_FRAME (current_frame);
173
174   /* now do the basic loop adding data until there is no more */
175   while (PREVIOUS_FRAME (current_frame) && i < TRACE_LIMIT)
176     {
177       table[i].return_pc = (void (*)())FRAME_PC (current_frame);
178 #ifdef SAVE_ARGS
179       for (j = 0; j < 3; j++)
180         table[i].arg[j] = frame_arg (&current_frame, j);
181 #endif
182       i++;
183     }
184   memset (&table[i], 0, sizeof (fun_entry) * (TRACE_LIMIT - i));
185 }
186
187 free_queue_entry *
188 find_backtrace (void *ptr)
189 {
190   int i;
191
192   for (i = 0; i < FREE_QUEUE_LIMIT; i++)
193     if (free_queue[i].address == ptr)
194       return &free_queue[i];
195
196   return 0;
197 }
198 #endif /* SAVE_STACK */
199
200 int strict_free_check;
201
202 static void
203 check_free (void *ptr)
204 {
205 #ifdef SAVE_STACK
206   FRAME start_frame;
207
208   init_frame (&start_frame);
209 #endif
210
211   __free_hook = 0;
212   __malloc_hook = 0;
213   if (!pointer_table)
214     pointer_table = make_hashtable (max (100, FREE_QUEUE_LIMIT * 2));
215   if (ptr != 0)
216     {
217       long size;
218 #ifdef UNMAPPED_FREE
219       unsigned long rounded_up_size;
220 #endif
221
222       EMACS_INT present = (EMACS_INT) gethash (ptr, pointer_table,
223                                                (CONST void **) &size);
224
225       if (!present)
226         {
227         /* This can only happen if you try to free something that didn't
228            come from malloc */
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)
233             abort ();
234 #endif
235           printf("Freeing unmalloc'ed memory at %p\n", ptr);
236           __free_hook = check_free;
237           __malloc_hook = check_malloc;
238           goto end;
239         }
240
241       if (size < 0)
242         {
243           /* This happens when you free twice */
244 #if !defined(__linux__)
245           /* See above comment. */
246           if (strict_free_check)
247             abort ();
248 #endif
249           printf("Freeing %p twice\n", ptr);
250           __free_hook = check_free;
251           __malloc_hook = check_malloc;
252           goto end;
253         }
254
255       puthash (ptr, (void *)-size, pointer_table);
256 #ifdef UNMAPPED_FREE
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);
262 #else
263       /* Set every word in the block to 0xdeadbeef */
264       if (strict_free_check)
265         {
266           unsigned long long_length = (size + (sizeof (long) - 1))
267             / sizeof (long);
268           unsigned long i;
269
270           for (i = 0; i < long_length; i++)
271             ((unsigned long *) ptr)[i] = 0xdeadbeef;
272         }
273 #endif
274       free_queue[current_free].address = ptr;
275       free_queue[current_free].length = size;
276 #ifdef SAVE_STACK
277       save_backtrace (&start_frame,
278                       free_queue[current_free].backtrace);
279 #endif
280       current_free++;
281       if (current_free >= FREE_QUEUE_LIMIT)
282         current_free = 0;
283       /* Really free this if there's something there */
284       {
285         void *old = free_queue[current_free].address;
286
287         if (old)
288           {
289 #ifdef UNMAPPED_FREE
290             unsigned long old_len = free_queue[current_free].length;
291
292             mprotect (old, old_len,  PROT_READ | PROT_WRITE | PROT_EXEC);
293 #endif
294             free (old);
295             remhash (old, pointer_table);
296           }
297       }
298     }
299   __free_hook = check_free;
300   __malloc_hook = check_malloc;
301
302  end:
303   return;
304 }
305
306 static void *
307 check_malloc (unsigned long size)
308 {
309   unsigned long rounded_up_size;
310   void *result;
311
312   __free_hook = 0;
313   __malloc_hook = 0;
314   if (size == 0)
315     {
316       result = 0;
317       goto end;
318     }
319 #ifdef UNMAPPED_FREE
320   /* Round up to an even number of pages. */
321   rounded_up_size = ROUND_UP_TO_PAGE (size);
322 #else
323   rounded_up_size = size;
324 #endif
325   result = malloc (rounded_up_size);
326   if (!pointer_table)
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;
331  end:
332   return result;
333 }
334
335 extern void *(*__realloc_hook) (void *, unsigned long);
336
337 #ifdef MIN
338 #undef MIN
339 #endif
340 #define MIN(A, B) ((A) < (B) ? (A) : (B))
341
342 /* Don't optimize realloc */
343
344 static void *
345 check_realloc (void * ptr, unsigned long size)
346 {
347   EMACS_INT present;
348   unsigned long old_size;
349   void *result = malloc (size);
350
351   if (!ptr) return result;
352   present = (EMACS_INT) gethash (ptr, pointer_table, (CONST void **) &old_size);
353   if (!present)
354     {
355     /* This can only happen by reallocing a pointer that didn't
356        come from malloc. */
357 #if !defined(__linux__)
358       /* see comment in check_free(). */
359       abort ();
360 #endif
361       printf("Realloc'ing unmalloc'ed pointer at %p\n", ptr);
362     }
363
364   if (result == 0)
365     goto end;
366   memcpy (result, ptr, MIN (size, old_size));
367   free (ptr);
368  end:
369   return result;
370 }
371
372 void enable_strict_free_check (void);
373 void
374 enable_strict_free_check (void)
375 {
376   strict_free_check = 1;
377 }
378
379 void disable_strict_free_check (void);
380 void
381 disable_strict_free_check (void)
382 {
383   strict_free_check = 0;
384 }
385
386 /* Note: All BLOCK_INPUT stuff removed from this file because it's
387    completely gone in XEmacs */
388
389 static void *
390 block_input_malloc (unsigned long size);
391
392 static void
393 block_input_free (void* ptr)
394 {
395   __free_hook = 0;
396   __malloc_hook = 0;
397   free (ptr);
398   __free_hook = block_input_free;
399   __malloc_hook = block_input_malloc;
400 }
401
402 static void *
403 block_input_malloc (unsigned long size)
404 {
405   void* result;
406   __free_hook = 0;
407   __malloc_hook = 0;
408   result = malloc (size);
409   __free_hook = block_input_free;
410   __malloc_hook = block_input_malloc;
411   return result;
412 }
413
414
415 static void *
416 block_input_realloc (void* ptr, unsigned long size)
417 {
418   void* result;
419   __free_hook = 0;
420   __malloc_hook = 0;
421   __realloc_hook = 0;
422   result = realloc (ptr, size);
423   __free_hook = block_input_free;
424   __malloc_hook = block_input_malloc;
425   __realloc_hook = block_input_realloc;
426   return result;
427 }
428
429 #ifdef emacs
430
431 void disable_free_hook (void);
432 void
433 disable_free_hook (void)
434 {
435   __free_hook = block_input_free;
436   __malloc_hook = block_input_malloc;
437   __realloc_hook = block_input_realloc;
438 }
439
440 void
441 init_free_hook (void)
442 {
443   __free_hook = check_free;
444   __malloc_hook = check_malloc;
445   __realloc_hook = check_realloc;
446   current_free = 0;
447   strict_free_check = 1;
448 }
449
450 void really_free_one_entry (void *, int, int *);
451
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.
455 */
456        (arg))
457 {
458   int count[2];
459   Lisp_Object lisp_count[2];
460
461   if ((__free_hook != 0) && pointer_table)
462     {
463       count[0] = 0;
464       count[1] = 0;
465       __free_hook = 0;
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);
469       current_free = 0;
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]);
474     }
475   else
476     return Fcons (make_int (0), make_int (0));
477 }
478
479 void
480 really_free_one_entry (void *key, int contents, int *countp)
481 {
482   if (contents < 0)
483     {
484       free (key);
485 #ifdef UNMAPPED_FREE
486       mprotect (key, -contents, PROT_READ | PROT_WRITE | PROT_EXEC);
487 #endif
488       remhash (key, pointer_table);
489       countp[0]++;
490       countp[1] += -contents;
491     }
492 }
493
494 void
495 syms_of_free_hook (void)
496 {
497   DEFSUBR (Freally_free);
498 }
499
500 #else
501 void (*__free_hook)() = check_free;
502 void *(*__malloc_hook)() = check_malloc;
503 void *(*__realloc_hook)() = check_realloc;
504 #endif
505
506 #endif /* !defined(HAVE_LIBMCHECK) */
507
508 #if defined(DEBUG_INPUT_BLOCKING) || defined (DEBUG_GCPRO)
509
510 /* Note: There is no more input blocking in XEmacs */
511 typedef enum {
512   block_type, unblock_type, totally_type,
513   gcpro1_type, gcpro2_type, gcpro3_type, gcpro4_type, ungcpro_type
514 } blocktype;
515
516 struct block_input_history_struct
517 {
518   char *file;
519   int line;
520   blocktype type;
521   int value;
522 #ifdef SAVE_STACK
523   fun_entry backtrace[TRACE_LIMIT];
524 #endif
525 };
526
527 typedef struct block_input_history_struct block_input_history;
528
529 #endif
530
531 #ifdef DEBUG_INPUT_BLOCKING
532
533 int blhistptr;
534
535 #define BLHISTLIMIT 1000
536
537 block_input_history blhist[BLHISTLIMIT];
538
539 note_block_input (char *file, int line)
540 {
541   note_block (file, line, block_type);
542   if (interrupt_input_blocked > 2) abort();
543 }
544
545 note_unblock_input (char* file, int line)
546 {
547   note_block (file, line, unblock_type);
548 }
549
550 note_totally_unblocked (char* file, int line)
551 {
552   note_block (file, line, totally_type);
553 }
554
555 note_block (char *file, int line, blocktype type)
556 {
557 #ifdef SAVE_STACK
558   FRAME start_frame;
559
560   init_frame (&start_frame);
561 #endif
562
563   blhist[blhistptr].file = file;
564   blhist[blhistptr].line = line;
565   blhist[blhistptr].type = type;
566   blhist[blhistptr].value = interrupt_input_blocked;
567
568 #ifdef SAVE_STACK
569   save_backtrace (&start_frame,
570                   blhist[blhistptr].backtrace);
571 #endif
572
573   blhistptr++;
574   if (blhistptr >= BLHISTLIMIT)
575     blhistptr = 0;
576 }
577
578 #endif
579
580 \f
581 #ifdef DEBUG_GCPRO
582
583 int gcprohistptr;
584 #define GCPROHISTLIMIT 1000
585 block_input_history gcprohist[GCPROHISTLIMIT];
586
587 static void
588 log_gcpro (char *file, int line, struct gcpro *value, blocktype type)
589 {
590   FRAME start_frame;
591
592   if (type == ungcpro_type)
593     {
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;
601       abort ();
602     OK:;
603     }
604 #ifdef SAVE_STACK
605   init_frame (&start_frame);
606 #endif
607   gcprohist[gcprohistptr].file = file;
608   gcprohist[gcprohistptr].line = line;
609   gcprohist[gcprohistptr].type = type;
610   gcprohist[gcprohistptr].value = (int) value;
611 #ifdef SAVE_STACK
612   save_backtrace (&start_frame, gcprohist[gcprohistptr].backtrace);
613 #endif
614   gcprohistptr++;
615   if (gcprohistptr >= GCPROHISTLIMIT)
616     gcprohistptr = 0;
617 }
618
619 void
620 debug_gcpro1 (char *file, int line, struct gcpro *gcpro1, Lisp_Object *var)
621 {
622   gcpro1->next = gcprolist; gcpro1->var = var; gcpro1->nvars = 1;
623   gcprolist = gcpro1;
624   log_gcpro (file, line, gcpro1, gcpro1_type);
625 }
626
627 void
628 debug_gcpro2 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
629               Lisp_Object *var1, Lisp_Object *var2)
630 {
631   gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
632   gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
633   gcprolist = gcpro2;
634   log_gcpro (file, line, gcpro2, gcpro2_type);
635 }
636
637 void
638 debug_gcpro3 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
639               struct gcpro *gcpro3, Lisp_Object *var1, Lisp_Object *var2,
640               Lisp_Object *var3)
641 {
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;
645   gcprolist = gcpro3;
646   log_gcpro (file, line, gcpro3, gcpro3_type);
647 }
648
649 void
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)
653 {
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;
659   gcprolist = gcpro4;
660 }
661
662 void
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)
667 {
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;
674   gcprolist = gcpro5;
675 }
676
677 void
678 debug_ungcpro (char *file, int line, struct gcpro *gcpro1)
679 {
680   log_gcpro (file, line, gcpro1, ungcpro_type);
681   gcprolist = gcpro1->next;
682 }
683
684 void
685 show_gcprohist (void)
686 {
687   int i, j;
688   for (i = 0, j = gcprohistptr;
689        i < GCPROHISTLIMIT;
690        i++, j++)
691     {
692       if (j >= GCPROHISTLIMIT)
693         j = 0;
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" : "???"),
701               gcprohist[j].value);
702     }
703   fflush (stdout);
704 }
705
706 #endif