comparison src/free-hook.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children abe6d1db359e
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
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
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 abort ();
495 OK:;
496 }
497 gcprohist[gcprohistptr].file = file;
498 gcprohist[gcprohistptr].line = line;
499 gcprohist[gcprohistptr].type = type;
500 gcprohist[gcprohistptr].value = (int) value;
501 gcprohistptr++;
502 if (gcprohistptr >= GCPROHISTLIMIT)
503 gcprohistptr = 0;
504 }
505
506 void
507 debug_gcpro1 (char *file, int line, struct gcpro *gcpro1, Lisp_Object *var)
508 {
509 gcpro1->next = gcprolist; gcpro1->var = var; gcpro1->nvars = 1;
510 gcprolist = gcpro1;
511 log_gcpro (file, line, gcpro1, gcpro1_type);
512 }
513
514 void
515 debug_gcpro2 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
516 Lisp_Object *var1, Lisp_Object *var2)
517 {
518 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
519 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
520 gcprolist = gcpro2;
521 log_gcpro (file, line, gcpro2, gcpro2_type);
522 }
523
524 void
525 debug_gcpro3 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
526 struct gcpro *gcpro3, Lisp_Object *var1, Lisp_Object *var2,
527 Lisp_Object *var3)
528 {
529 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
530 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
531 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
532 gcprolist = gcpro3;
533 log_gcpro (file, line, gcpro3, gcpro3_type);
534 }
535
536 void
537 debug_gcpro4 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
538 struct gcpro *gcpro3, struct gcpro *gcpro4, Lisp_Object *var1,
539 Lisp_Object *var2, Lisp_Object *var3, Lisp_Object *var4)
540 {
541 log_gcpro (file, line, gcpro4, gcpro4_type);
542 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
543 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
544 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
545 gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
546 gcprolist = gcpro4;
547 }
548
549 void
550 debug_gcpro5 (char *file, int line, struct gcpro *gcpro1, struct gcpro *gcpro2,
551 struct gcpro *gcpro3, struct gcpro *gcpro4, struct gcpro *gcpro5,
552 Lisp_Object *var1, Lisp_Object *var2, Lisp_Object *var3,
553 Lisp_Object *var4, Lisp_Object *var5)
554 {
555 log_gcpro (file, line, gcpro5, gcpro5_type);
556 gcpro1->next = gcprolist; gcpro1->var = var1; gcpro1->nvars = 1;
557 gcpro2->next = gcpro1; gcpro2->var = var2; gcpro2->nvars = 1;
558 gcpro3->next = gcpro2; gcpro3->var = var3; gcpro3->nvars = 1;
559 gcpro4->next = gcpro3; gcpro4->var = var4; gcpro4->nvars = 1;
560 gcpro5->next = gcpro4; gcpro5->var = var5; gcpro5->nvars = 1;
561 gcprolist = gcpro5;
562 }
563
564 void
565 debug_ungcpro (char *file, int line, struct gcpro *gcpro1)
566 {
567 log_gcpro (file, line, gcpro1, ungcpro_type);
568 gcprolist = gcpro1->next;
569 }
570
571
572 /* To be called from the debugger */
573 void show_gcprohist (void);
574 void
575 show_gcprohist (void)
576 {
577 int i, j;
578 for (i = 0, j = gcprohistptr;
579 i < GCPROHISTLIMIT;
580 i++, j++)
581 {
582 if (j >= GCPROHISTLIMIT)
583 j = 0;
584 printf ("%3d %s %d %s 0x%x\n",
585 j, gcprohist[j].file, gcprohist[j].line,
586 (gcprohist[j].type == gcpro1_type ? "GCPRO1" :
587 gcprohist[j].type == gcpro2_type ? "GCPRO2" :
588 gcprohist[j].type == gcpro3_type ? "GCPRO3" :
589 gcprohist[j].type == gcpro4_type ? "GCPRO4" :
590 gcprohist[j].type == ungcpro_type ? "UNGCPRO" : "???"),
591 gcprohist[j].value);
592 }
593 fflush (stdout);
594 }
595
596 #endif /* DEBUG_GCPRO */