(U-000221C7): Add `sound@ja/on'; integrate BC-8BD8.
[chise/xemacs-chise.git] / 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 #ifdef emacs
66 #include <config.h>
67 #include "lisp.h"
68 #else
69 void *malloc (size_t);
70 #endif
71
72 #if !defined(HAVE_LIBMCHECK)
73 #include <stdio.h>
74
75 #include "hash.h"
76
77 #ifdef UNMAPPED_FREE
78 #include <sys/mman.h>
79 #include <sys/param.h>
80 #define ROUND_UP_TO_PAGE(i) (((i) + PAGEOFFSET) & PAGEMASK)
81 #endif
82
83 #include <sys/types.h>
84
85 /* System function prototypes don't belong in C source files */
86 /* extern void free (void *); */
87
88 static struct hash_table *pointer_table;
89
90 extern void (*__free_hook) (void *);
91 extern void *(*__malloc_hook) (size_t);
92
93 static void *check_malloc (size_t);
94
95 typedef void (*fun_ptr) (void);
96
97 /* free_queue is not too useful without backtrace logging */
98 #define FREE_QUEUE_LIMIT 1
99 #define TRACE_LIMIT 20
100
101 typedef struct {
102   fun_ptr return_pc;
103 #ifdef SAVE_ARGS
104   void *arg[3];
105 #endif
106 } fun_entry;
107
108 typedef struct {
109   void *address;
110   unsigned long length;
111 } free_queue_entry;
112
113 static free_queue_entry free_queue[FREE_QUEUE_LIMIT];
114
115 static int current_free;
116
117 static int strict_free_check;
118
119 static void
120 check_free (void *ptr)
121 {
122   __free_hook = 0;
123   __malloc_hook = 0;
124   if (!pointer_table)
125     pointer_table = make_hash_table (max (100, FREE_QUEUE_LIMIT * 2));
126   if (ptr != 0)
127     {
128       long size;
129 #ifdef UNMAPPED_FREE
130       unsigned long rounded_up_size;
131 #endif
132
133       EMACS_INT present = (EMACS_INT) gethash (ptr, pointer_table,
134                                                (const void **) &size);
135
136       if (!present)
137         {
138         /* This can only happen if you try to free something that didn't
139            come from malloc */
140 #if !defined(__linux__)
141           /* I originally wrote:  "There's really no need to drop core."
142              I have seen the error of my ways. -slb */
143           if (strict_free_check)
144             ABORT ();
145 #endif
146           printf("Freeing unmalloc'ed memory at %p\n", ptr);
147           __free_hook = check_free;
148           __malloc_hook = check_malloc;
149           goto end;
150         }
151
152       if (size < 0)
153         {
154           /* This happens when you free twice */
155 #if !defined(__linux__)
156           /* See above comment. */
157           if (strict_free_check)
158             ABORT ();
159 #endif
160           printf("Freeing %p twice\n", ptr);
161           __free_hook = check_free;
162           __malloc_hook = check_malloc;
163           goto end;
164         }
165
166       puthash (ptr, (void *)-size, pointer_table);
167 #ifdef UNMAPPED_FREE
168       /* Round up size to an even number of pages. */
169       rounded_up_size = ROUND_UP_TO_PAGE (size);
170       /* Protect the pages freed from all access */
171       if (strict_free_check)
172         mprotect (ptr, rounded_up_size, PROT_NONE);
173 #else
174       /* Set every word in the block to 0xdeadbeef */
175       if (strict_free_check)
176         {
177           unsigned long long_length = (size + (sizeof (long) - 1))
178             / sizeof (long);
179           unsigned long i;
180
181           for (i = 0; i < long_length; i++)
182             ((unsigned long *) ptr)[i] = 0xdeadbeef;
183         }
184 #endif
185       free_queue[current_free].address = ptr;
186       free_queue[current_free].length = size;
187
188       current_free++;
189       if (current_free >= FREE_QUEUE_LIMIT)
190         current_free = 0;
191       /* Really free this if there's something there */
192       {
193         void *old = free_queue[current_free].address;
194
195         if (old)
196           {
197 #ifdef UNMAPPED_FREE
198             unsigned long old_len = free_queue[current_free].length;
199
200             mprotect (old, old_len,  PROT_READ | PROT_WRITE | PROT_EXEC);
201 #endif
202             free (old);
203             remhash (old, pointer_table);
204           }
205       }
206     }
207   __free_hook = check_free;
208   __malloc_hook = check_malloc;
209
210  end:
211   return;
212 }
213
214 static void *
215 check_malloc (size_t size)
216 {
217   size_t rounded_up_size;
218   void *result;
219
220   __free_hook = 0;
221   __malloc_hook = 0;
222   if (size == 0)
223     {
224       result = 0;
225       goto end;
226     }
227 #ifdef UNMAPPED_FREE
228   /* Round up to an even number of pages. */
229   rounded_up_size = ROUND_UP_TO_PAGE (size);
230 #else
231   rounded_up_size = size;
232 #endif
233   result = malloc (rounded_up_size);
234   if (!pointer_table)
235     pointer_table = make_hash_table (FREE_QUEUE_LIMIT * 2);
236   puthash (result, (void *)size, pointer_table);
237   __free_hook = check_free;
238   __malloc_hook = check_malloc;
239  end:
240   return result;
241 }
242
243 extern void *(*__realloc_hook) (void *, size_t);
244
245 #ifdef MIN
246 #undef MIN
247 #endif
248 #define MIN(A, B) ((A) < (B) ? (A) : (B))
249
250 /* Don't optimize realloc */
251
252 static void *
253 check_realloc (void * ptr, size_t size)
254 {
255   EMACS_INT present;
256   size_t old_size;
257   void *result = malloc (size);
258
259   if (!ptr) return result;
260   present = (EMACS_INT) gethash (ptr, pointer_table, (const void **) &old_size);
261   if (!present)
262     {
263     /* This can only happen by reallocing a pointer that didn't
264        come from malloc. */
265 #if !defined(__linux__)
266       /* see comment in check_free(). */
267       ABORT ();
268 #endif
269       printf("Realloc'ing unmalloc'ed pointer at %p\n", ptr);
270     }
271
272   if (result == 0)
273     goto end;
274   memcpy (result, ptr, MIN (size, old_size));
275   free (ptr);
276  end:
277   return result;
278 }
279
280 void enable_strict_free_check (void);
281 void
282 enable_strict_free_check (void)
283 {
284   strict_free_check = 1;
285 }
286
287 void disable_strict_free_check (void);
288 void
289 disable_strict_free_check (void)
290 {
291   strict_free_check = 0;
292 }
293
294 /* Note: All BLOCK_INPUT stuff removed from this file because it's
295    completely gone in XEmacs */
296
297 static void *
298 block_input_malloc (size_t size);
299
300 static void
301 block_input_free (void* ptr)
302 {
303   __free_hook = 0;
304   __malloc_hook = 0;
305   free (ptr);
306   __free_hook = block_input_free;
307   __malloc_hook = block_input_malloc;
308 }
309
310 static void *
311 block_input_malloc (size_t size)
312 {
313   void* result;
314   __free_hook = 0;
315   __malloc_hook = 0;
316   result = malloc (size);
317   __free_hook = block_input_free;
318   __malloc_hook = block_input_malloc;
319   return result;
320 }
321
322
323 static void *
324 block_input_realloc (void* ptr, size_t size)
325 {
326   void* result;
327   __free_hook = 0;
328   __malloc_hook = 0;
329   __realloc_hook = 0;
330   result = realloc (ptr, size);
331   __free_hook = block_input_free;
332   __malloc_hook = block_input_malloc;
333   __realloc_hook = block_input_realloc;
334   return result;
335 }
336
337 #ifdef emacs
338
339 void disable_free_hook (void);
340 void
341 disable_free_hook (void)
342 {
343   __free_hook = block_input_free;
344   __malloc_hook = block_input_malloc;
345   __realloc_hook = block_input_realloc;
346 }
347
348 void
349 init_free_hook (void)
350 {
351   __free_hook = check_free;
352   __malloc_hook = check_malloc;
353   __realloc_hook = check_realloc;
354   current_free = 0;
355   strict_free_check = 1;
356 }
357
358 void really_free_one_entry (void *, int, int *);
359
360 DEFUN ("really-free", Freally_free, 0, 1, "P", /*
361 Actually free the storage held by the free() debug hook.
362 A no-op if the free hook is disabled.
363 */
364        (arg))
365 {
366   int count[2];
367   Lisp_Object lisp_count[2];
368
369   if ((__free_hook != 0) && pointer_table)
370     {
371       count[0] = 0;
372       count[1] = 0;
373       __free_hook = 0;
374       maphash ((maphash_function)really_free_one_entry,
375                pointer_table, (void *)&count);
376       memset (free_queue, 0, sizeof (free_queue_entry) * FREE_QUEUE_LIMIT);
377       current_free = 0;
378       __free_hook = check_free;
379       XSETINT (lisp_count[0], count[0]);
380       XSETINT (lisp_count[1], count[1]);
381       return Fcons (lisp_count[0], lisp_count[1]);
382     }
383   else
384     return Fcons (make_int (0), make_int (0));
385 }
386
387 void
388 really_free_one_entry (void *key, int contents, int *countp)
389 {
390   if (contents < 0)
391     {
392       free (key);
393 #ifdef UNMAPPED_FREE
394       mprotect (key, -contents, PROT_READ | PROT_WRITE | PROT_EXEC);
395 #endif
396       remhash (key, pointer_table);
397       countp[0]++;
398       countp[1] += -contents;
399     }
400 }
401
402 void
403 syms_of_free_hook (void)
404 {
405   DEFSUBR (Freally_free);
406 }
407
408 #else
409 void (*__free_hook)(void *) = check_free;
410 void *(*__malloc_hook)(size_t) = check_malloc;
411 void *(*__realloc_hook)(void *, size_t) = check_realloc;
412 #endif
413
414 #endif /* !defined(HAVE_LIBMCHECK) */
415
416 #if defined(DEBUG_INPUT_BLOCKING) || defined (DEBUG_GCPRO)
417
418 /* Note: There is no more input blocking in XEmacs */
419 typedef enum {
420   block_type, unblock_type, totally_type,
421   gcpro1_type, gcpro2_type, gcpro3_type, gcpro4_type, gcpro5_type,
422   ungcpro_type
423 } blocktype;
424
425 struct block_input_history_struct
426 {
427   char *file;
428   int line;
429   blocktype type;
430   int value;
431 };
432
433 typedef struct block_input_history_struct block_input_history;
434
435 #endif /* DEBUG_INPUT_BLOCKING || DEBUG_GCPRO */
436
437 #ifdef DEBUG_INPUT_BLOCKING
438
439 int blhistptr;
440
441 #define BLHISTLIMIT 1000
442
443 block_input_history blhist[BLHISTLIMIT];
444
445 note_block_input (char *file, int line)
446 {
447   note_block (file, line, block_type);
448   if (interrupt_input_blocked > 2) ABORT();
449 }
450
451 note_unblock_input (char* file, int line)
452 {
453   note_block (file, line, unblock_type);
454 }
455
456 note_totally_unblocked (char* file, int line)
457 {
458   note_block (file, line, totally_type);
459 }
460
461 note_block (char *file, int line, blocktype type)
462 {
463   blhist[blhistptr].file = file;
464   blhist[blhistptr].line = line;
465   blhist[blhistptr].type = type;
466   blhist[blhistptr].value = interrupt_input_blocked;
467
468   blhistptr++;
469   if (blhistptr >= BLHISTLIMIT)
470     blhistptr = 0;
471 }
472
473 #endif /* DEBUG_INPUT_BLOCKING */
474
475 \f
476 #ifdef DEBUG_GCPRO
477
478 int gcprohistptr;
479 #define GCPROHISTLIMIT 1000
480 block_input_history gcprohist[GCPROHISTLIMIT];
481
482 static void
483 log_gcpro (char *file, int line, struct gcpro *value, blocktype type)
484 {
485   if (type == ungcpro_type)
486     {
487       if (value == gcprolist) goto OK;
488       if (! gcprolist) ABORT ();
489       if (value == gcprolist->next) goto OK;
490       if (! gcprolist->next) ABORT ();
491       if (value == gcprolist->next->next) goto OK;
492       if (! gcprolist->next->next) ABORT ();
493       if (value == gcprolist->next->next->next) goto OK;
494       if (! gcprolist->next->next->next) ABORT ();
495       if (value == gcprolist->next->next->next->next) goto OK;
496       ABORT ();
497     OK:;
498     }
499   gcprohist[gcprohistptr].file = file;
500   gcprohist[gcprohistptr].line = line;
501   gcprohist[gcprohistptr].type = type;
502   gcprohist[gcprohistptr].value = (int) value;
503   gcprohistptr++;
504   if (gcprohistptr >= GCPROHISTLIMIT)
505     gcprohistptr = 0;
506 }
507
508 void
509 debug_gcpro1 (char *file, int line, struct gcpro *gcpro1, Lisp_Object *var)
510 {
511   gcpro1->next = gcprolist; gcpro1->var = var; gcpro1->nvars = 1;
512   gcprolist = gcpro1;
513   log_gcpro (file, line, gcpro1, gcpro1_type);
514 }
515
516 void
517 debug_gcpro2 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
518               Lisp_Object *var1, Lisp_Object *var2)
519 {
520   gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
521   gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
522   gcprolist = gcpro2;
523   log_gcpro (file, line, gcpro2, gcpro2_type);
524 }
525
526 void
527 debug_gcpro3 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
528               struct gcpro *gcpro3, Lisp_Object *var1, Lisp_Object *var2,
529               Lisp_Object *var3)
530 {
531   gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
532   gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
533   gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
534   gcprolist = gcpro3;
535   log_gcpro (file, line, gcpro3, gcpro3_type);
536 }
537
538 void
539 debug_gcpro4 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
540               struct gcpro *gcpro3, struct gcpro *gcpro4, Lisp_Object *var1,
541               Lisp_Object *var2, Lisp_Object *var3, Lisp_Object *var4)
542 {
543   log_gcpro (file, line, gcpro4, gcpro4_type);
544   gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
545   gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
546   gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
547   gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
548   gcprolist = gcpro4;
549 }
550
551 void
552 debug_gcpro5 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
553               struct gcpro *gcpro3, struct gcpro *gcpro4, struct gcpro *gcpro5,
554               Lisp_Object *var1, Lisp_Object *var2, Lisp_Object *var3,
555               Lisp_Object *var4, Lisp_Object *var5)
556 {
557   log_gcpro (file, line, gcpro5, gcpro5_type);
558   gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
559   gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
560   gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
561   gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
562   gcpro5->next = gcpro4; gcpro5->var = var5; gcpro5->nvars = 1;
563   gcprolist = gcpro5;
564 }
565
566 void
567 debug_ungcpro (char *file, int line, struct gcpro *gcpro1)
568 {
569   log_gcpro (file, line, gcpro1, ungcpro_type);
570   gcprolist = gcpro1->next;
571 }
572
573
574 /* To be called from the debugger */
575 void show_gcprohist (void);
576 void
577 show_gcprohist (void)
578 {
579   int i, j;
580   for (i = 0, j = gcprohistptr;
581        i < GCPROHISTLIMIT;
582        i++, j++)
583     {
584       if (j >= GCPROHISTLIMIT)
585         j = 0;
586       printf ("%3d  %s          %d      %s      0x%x\n",
587               j, gcprohist[j].file, gcprohist[j].line,
588               (gcprohist[j].type == gcpro1_type ? "GCPRO1" :
589                gcprohist[j].type == gcpro2_type ? "GCPRO2" :
590                gcprohist[j].type == gcpro3_type ? "GCPRO3" :
591                gcprohist[j].type == gcpro4_type ? "GCPRO4" :
592                gcprohist[j].type == gcpro5_type ? "GCPRO5" :
593                gcprohist[j].type == ungcpro_type ? "UNGCPRO" : "???"),
594               gcprohist[j].value);
595     }
596   fflush (stdout);
597 }
598
599 #endif /* DEBUG_GCPRO */