]>
git.zerfleddert.de Git - micropolis/blob - src/tcl/tclckall.c
3 * Interface to malloc and free that provides support for debugging problems
4 * involving overwritten, double freeing memory and loss of memory.
6 * Copyright 1991 Regents of the University of California
7 * Permission to use, copy, modify, and distribute this
8 * software and its documentation for any purpose and without
9 * fee is hereby granted, provided that the above copyright
10 * notice appear in all copies. The University of California
11 * makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without
13 * express or implied warranty.
15 * This code contributed by Karl Lehenbauer and Mark Diekhans
25 #ifndef TCL_GENERIC_ONLY
35 struct mem_header
*flink
;
36 struct mem_header
*blink
;
37 unsigned char low_guard
[GUARD_SIZE
];
41 static struct mem_header
*allocHead
= NULL
; /* List of allocated structures */
43 #define GUARD_VALUE 0341
45 /* static char high_guard[] = {0x89, 0xab, 0xcd, 0xef}; */
47 static int total_mallocs
= 0;
48 static int total_frees
= 0;
49 static int current_bytes_malloced
= 0;
50 static int maximum_bytes_malloced
= 0;
51 static int current_malloc_packets
= 0;
52 static int maximum_malloc_packets
= 0;
53 static int break_on_malloc
= 0;
54 static int trace_on_at_malloc
= 0;
55 static int alloc_tracing
= FALSE
;
56 static int init_malloced_bodies
= FALSE
;
58 static int validate_memory
= TRUE
;
60 static int validate_memory
= FALSE
;
65 *----------------------------------------------------------------------
68 * Display the global memory management statistics.
70 *----------------------------------------------------------------------
73 dump_memory_info(outFile
)
76 fprintf(outFile
,"total mallocs %10d\n",
78 fprintf(outFile
,"total frees %10d\n",
80 fprintf(outFile
,"current packets allocated %10d\n",
81 current_malloc_packets
);
82 fprintf(outFile
,"current bytes allocated %10d\n",
83 current_bytes_malloced
);
84 fprintf(outFile
,"maximum packets allocated %10d\n",
85 maximum_malloc_packets
);
86 fprintf(outFile
,"maximum bytes allocated %10d\n",
87 maximum_bytes_malloced
);
91 *----------------------------------------------------------------------
94 * Procedure to validate allocted memory guard zones.
96 *----------------------------------------------------------------------
99 ValidateMemory (memHeaderP
, file
, line
, nukeGuards
)
100 struct mem_header
*memHeaderP
;
105 unsigned char *hiPtr
;
107 int guard_failed
= FALSE
;
109 for (idx
= 0; idx
< GUARD_SIZE
; idx
++)
110 if (*(memHeaderP
->low_guard
+ idx
) != GUARD_VALUE
) {
113 fprintf(stderr
, "low guard byte %d is 0x%x\n", idx
,
114 *(memHeaderP
->low_guard
+ idx
) & 0xff);
118 dump_memory_info (stderr
);
119 fprintf (stderr
, "low guard failed at %lx, %s %d\n",
120 memHeaderP
->body
, file
, line
);
121 fflush (stderr
); /* In case name pointer is bad. */
122 fprintf (stderr
, "Allocated at (%s %d)\n", memHeaderP
->file
,
124 panic ("Memory validation failure");
127 hiPtr
= (unsigned char *)memHeaderP
->body
+ memHeaderP
->length
;
128 for (idx
= 0; idx
< GUARD_SIZE
; idx
++)
129 if (*(hiPtr
+ idx
) != GUARD_VALUE
) {
132 fprintf(stderr
, "hi guard byte %d is 0x%x\n", idx
,
133 *(hiPtr
+idx
) & 0xff);
137 dump_memory_info (stderr
);
138 fprintf (stderr
, "high guard failed at %lx, %s %d\n",
139 memHeaderP
->body
, file
, line
);
140 fflush (stderr
); /* In case name pointer is bad. */
141 fprintf (stderr
, "Allocated at (%s %d)\n", memHeaderP
->file
,
143 panic ("Memory validation failure");
147 memset ((char *) memHeaderP
->low_guard
, 0, GUARD_SIZE
);
148 memset ((char *) hiPtr
, 0, GUARD_SIZE
);
154 *----------------------------------------------------------------------
156 * Tcl_ValidateAllMemory --
157 * Validates guard regions for all allocated memory.
159 *----------------------------------------------------------------------
162 Tcl_ValidateAllMemory (file
, line
)
166 struct mem_header
*memScanP
;
168 for (memScanP
= allocHead
; memScanP
!= NULL
; memScanP
= memScanP
->flink
)
169 ValidateMemory (memScanP
, file
, line
, FALSE
);
174 *----------------------------------------------------------------------
176 * Tcl_DumpActiveMemory --
177 * Displays all allocated memory to stderr.
180 * Return TCL_ERROR if an error accessing the file occures, `errno'
181 * will have the file error number left in it.
182 *----------------------------------------------------------------------
185 Tcl_DumpActiveMemory (fileName
)
189 struct mem_header
*memScanP
;
193 fileP
= fopen (fileName
, "wb");
195 fileP
= fopen (fileName
, "w");
200 for (memScanP
= allocHead
; memScanP
!= NULL
; memScanP
= memScanP
->flink
) {
201 address
= &memScanP
->body
[0];
202 fprintf (fileP
, "%8lx - %8lx %7d @ %s %d\n", address
,
203 address
+ memScanP
->length
- 1, memScanP
->length
,
204 memScanP
->file
, memScanP
->line
);
211 *----------------------------------------------------------------------
213 * Tcl_DbCkalloc - debugging ckalloc
215 * Allocate the requested amount of space plus some extra for
216 * guard bands at both ends of the request, plus a size, panicing
217 * if there isn't enough space, then write in the guard bands
218 * and return the address of the space in the middle that the
221 * The second and third arguments are file and line, these contain
222 * the filename and line number corresponding to the caller.
223 * These are sent by the ckalloc macro; it uses the preprocessor
224 * autodefines __FILE__ and __LINE__.
226 *----------------------------------------------------------------------
229 Tcl_DbCkalloc(size
, file
, line
)
234 struct mem_header
*result
;
237 Tcl_ValidateAllMemory (file
, line
);
239 result
= (struct mem_header
*)malloc((unsigned)size
+
240 sizeof(struct mem_header
) + GUARD_SIZE
);
241 if (result
== NULL
) {
243 dump_memory_info(stderr
);
244 panic("unable to alloc %d bytes, %s line %d", size
, file
,
249 * Fill in guard zones and size. Link into allocated list.
251 result
->length
= size
;
254 memset ((char *) result
->low_guard
, GUARD_VALUE
, GUARD_SIZE
);
255 memset (result
->body
+ size
, GUARD_VALUE
, GUARD_SIZE
);
256 result
->flink
= allocHead
;
257 result
->blink
= NULL
;
258 if (allocHead
!= NULL
)
259 allocHead
->blink
= result
;
263 if (trace_on_at_malloc
&& (total_mallocs
>= trace_on_at_malloc
)) {
264 (void) fflush(stdout
);
265 fprintf(stderr
, "reached malloc trace enable point (%d)\n",
268 alloc_tracing
= TRUE
;
269 trace_on_at_malloc
= 0;
273 fprintf(stderr
,"ckalloc %lx %d %s %d\n", result
->body
, size
,
276 if (break_on_malloc
&& (total_mallocs
>= break_on_malloc
)) {
278 (void) fflush(stdout
);
279 fprintf(stderr
,"reached malloc break limit (%d)\n",
281 fprintf(stderr
, "program will now enter C debugger\n");
282 (void) fflush(stderr
);
283 kill (getpid(), SIGINT
);
286 current_malloc_packets
++;
287 if (current_malloc_packets
> maximum_malloc_packets
)
288 maximum_malloc_packets
= current_malloc_packets
;
289 current_bytes_malloced
+= size
;
290 if (current_bytes_malloced
> maximum_bytes_malloced
)
291 maximum_bytes_malloced
= current_bytes_malloced
;
293 if (init_malloced_bodies
)
294 memset (result
->body
, 0xff, (int) size
);
300 *----------------------------------------------------------------------
302 * Tcl_DbCkfree - debugging ckfree
304 * Verify that the low and high guards are intact, and if so
305 * then free the buffer else panic.
307 * The guards are erased after being checked to catch duplicate
310 * The second and third arguments are file and line, these contain
311 * the filename and line number corresponding to the caller.
312 * These are sent by the ckfree macro; it uses the preprocessor
313 * autodefines __FILE__ and __LINE__.
315 *----------------------------------------------------------------------
319 Tcl_DbCkfree(ptr
, file
, line
)
324 struct mem_header
*memp
= 0; /* Must be zero for size calc */
327 * Since header ptr is zero, body offset will be size
329 memp
= (struct mem_header
*)(((char *) ptr
) - (int)memp
->body
);
332 fprintf(stderr
, "ckfree %lx %ld %s %d\n", memp
->body
,
333 memp
->length
, file
, line
);
336 Tcl_ValidateAllMemory (file
, line
);
338 ValidateMemory (memp
, file
, line
, TRUE
);
341 current_malloc_packets
--;
342 current_bytes_malloced
-= memp
->length
;
345 * Delink from allocated list
347 if (memp
->flink
!= NULL
)
348 memp
->flink
->blink
= memp
->blink
;
349 if (memp
->blink
!= NULL
)
350 memp
->blink
->flink
= memp
->flink
;
351 if (allocHead
== memp
)
352 allocHead
= memp
->flink
;
358 *----------------------------------------------------------------------
361 * Implements the TCL memory command:
364 * break_on_malloc count
365 * trace_on_at_malloc count
370 * Standard TCL results.
372 *----------------------------------------------------------------------
376 MemoryCmd (clientData
, interp
, argc
, argv
)
385 Tcl_AppendResult(interp
, "wrong # args: should be \"",
386 argv
[0], " option [args..]\"", (char *) NULL
);
390 if (strcmp(argv
[1],"trace") == 0) {
393 alloc_tracing
= (strcmp(argv
[2],"on") == 0);
396 if (strcmp(argv
[1],"init") == 0) {
399 init_malloced_bodies
= (strcmp(argv
[2],"on") == 0);
402 if (strcmp(argv
[1],"validate") == 0) {
405 validate_memory
= (strcmp(argv
[2],"on") == 0);
408 if (strcmp(argv
[1],"trace_on_at_malloc") == 0) {
411 if (Tcl_GetInt(interp
, argv
[2], &trace_on_at_malloc
) != TCL_OK
)
415 if (strcmp(argv
[1],"break_on_malloc") == 0) {
418 if (Tcl_GetInt(interp
, argv
[2], &break_on_malloc
) != TCL_OK
)
423 if (strcmp(argv
[1],"info") == 0) {
424 dump_memory_info(stdout
);
427 if (strcmp(argv
[1],"active") == 0) {
429 Tcl_AppendResult(interp
, "wrong # args: should be \"",
430 argv
[0], " active file", (char *) NULL
);
434 if (fileName
[0] == '~')
435 if ((fileName
= Tcl_TildeSubst (interp
, fileName
)) == NULL
)
437 if (Tcl_DumpActiveMemory (fileName
) != TCL_OK
) {
438 Tcl_AppendResult(interp
, "error accessing ", argv
[2],
444 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
445 "\": should be info, init, active, break_on_malloc, ",
446 "trace_on_at_malloc, trace, or validate", (char *) NULL
);
450 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
451 " ", argv
[1], "count\"", (char *) NULL
);
455 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
456 " ", argv
[1], " on|off\"", (char *) NULL
);
461 *----------------------------------------------------------------------
464 * Initialize the memory command.
466 *----------------------------------------------------------------------
469 Tcl_InitMemory(interp
)
472 Tcl_CreateCommand (interp
, "memory", MemoryCmd
, (ClientData
)NULL
,
480 *----------------------------------------------------------------------
483 * Interface to malloc when TCL_MEM_DEBUG is disabled. It does check
484 * that memory was actually allocated.
486 *----------------------------------------------------------------------
494 result
= malloc(size
);
496 panic("unable to alloc %d bytes", size
);
501 *----------------------------------------------------------------------
504 * Interface to free when TCL_MEM_DEBUG is disabled. Done here rather
505 * in the macro to keep some modules from being compiled with
506 * TCL_MEM_DEBUG enabled and some with it disabled.
508 *----------------------------------------------------------------------
518 *----------------------------------------------------------------------
521 * Dummy initialization for memory command, which is only available
522 * if TCL_MEM_DEBUG is on.
524 *----------------------------------------------------------------------
528 Tcl_InitMemory(interp
)