4 * Interface to malloc and free that provides support for debugging problems
5 * involving overwritten, double freeing memory and loss of memory.
7 * Copyright (c) 1991-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
9 * Copyright (c) 1998-1999 by Scriptics Corporation.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * This code contributed by Karl Lehenbauer and Mark Diekhans
28 * One of the following structures is allocated each time the
29 * "memory tag" command is invoked, to hold the current tag.
32 typedef struct MemTag {
33 int refCount; /* Number of mem_headers referencing
35 char string[4]; /* Actual size of string will be as
36 * large as needed for actual tag. This
37 * must be the last field in the structure. */
40 #define TAG_SIZE(bytesInString) ((unsigned) sizeof(MemTag) + bytesInString - 3)
42 static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers
43 * (set by "memory tag" command). */
46 * One of the following structures is allocated just before each
47 * dynamically allocated chunk of memory, both to record information
48 * about the chunk and to help detect chunk under-runs.
51 #define LOW_GUARD_SIZE (8 + (32 - (sizeof(long) + sizeof(int)))%8)
53 struct mem_header *flink;
54 struct mem_header *blink;
55 MemTag *tagPtr; /* Tag from "memory tag" command; may be
60 unsigned char low_guard[LOW_GUARD_SIZE];
61 /* Aligns body on 8-byte boundary, plus
62 * provides at least 8 additional guard bytes
63 * to detect underruns. */
64 char body[1]; /* First byte of client's space. Actual
65 * size of this field will be larger than
69 static struct mem_header *allocHead = NULL; /* List of allocated structures */
71 #define GUARD_VALUE 0141
74 * The following macro determines the amount of guard space *above* each
78 #define HIGH_GUARD_SIZE 8
81 * The following macro computes the offset of the "body" field within
82 * mem_header. It is used to get back to the header pointer from the
83 * body pointer that's used by clients.
87 ((unsigned long) (&((struct mem_header *) 0)->body))
89 static int total_mallocs = 0;
90 static int total_frees = 0;
91 static int current_bytes_malloced = 0;
92 static int maximum_bytes_malloced = 0;
93 static int current_malloc_packets = 0;
94 static int maximum_malloc_packets = 0;
95 static int break_on_malloc = 0;
96 static int trace_on_at_malloc = 0;
97 static int alloc_tracing = FALSE;
98 static int init_malloced_bodies = TRUE;
100 static int validate_memory = TRUE;
102 static int validate_memory = FALSE;
106 * The following variable indicates to TclFinalizeMemorySubsystem()
107 * that it should dump out the state of memory before exiting. If the
108 * value is non-NULL, it gives the name of the file in which to
109 * dump memory usage information.
112 char *tclMemDumpFileName = NULL;
114 static char *onExitMemDumpFileName = NULL;
115 static char dumpFile[100]; /* Records where to dump memory allocation
119 * Mutex to serialize allocations. This is a low-level mutex that must
120 * be explicitly initialized. This is necessary because the self
121 * initializing mutexes use ckalloc...
123 static Tcl_Mutex *ckallocMutexPtr;
124 static int ckallocInit = 0;
127 * Prototypes for procedures defined in this file:
130 static int CheckmemCmd _ANSI_ARGS_((ClientData clientData,
131 Tcl_Interp *interp, int argc, CONST char *argv[]));
132 static int MemoryCmd _ANSI_ARGS_((ClientData clientData,
133 Tcl_Interp *interp, int argc, CONST char **argv));
134 static void ValidateMemory _ANSI_ARGS_((
135 struct mem_header *memHeaderP, CONST char *file,
136 int line, int nukeGuards));
139 *----------------------------------------------------------------------
141 * TclInitDbCkalloc --
142 * Initialize the locks used by the allocator.
143 * This is only appropriate to call in a single threaded environment,
144 * such as during TclInitSubsystems.
146 *----------------------------------------------------------------------
153 ckallocMutexPtr = Tcl_GetAllocMutex();
158 *----------------------------------------------------------------------
160 * TclDumpMemoryInfo --
161 * Display the global memory management statistics.
163 *----------------------------------------------------------------------
166 TclDumpMemoryInfo(outFile)
169 fprintf(outFile,"total mallocs %10d\n",
171 fprintf(outFile,"total frees %10d\n",
173 fprintf(outFile,"current packets allocated %10d\n",
174 current_malloc_packets);
175 fprintf(outFile,"current bytes allocated %10d\n",
176 current_bytes_malloced);
177 fprintf(outFile,"maximum packets allocated %10d\n",
178 maximum_malloc_packets);
179 fprintf(outFile,"maximum bytes allocated %10d\n",
180 maximum_bytes_malloced);
185 *----------------------------------------------------------------------
189 * Validate memory guard zones for a particular chunk of allocated
196 * Prints validation information about the allocated memory to stderr.
198 *----------------------------------------------------------------------
202 ValidateMemory(memHeaderP, file, line, nukeGuards)
203 struct mem_header *memHeaderP; /* Memory chunk to validate */
204 CONST char *file; /* File containing the call to
205 * Tcl_ValidateAllMemory */
206 int line; /* Line number of call to
207 * Tcl_ValidateAllMemory */
208 int nukeGuards; /* If non-zero, indicates that the
209 * memory guards are to be reset to 0
210 * after they have been printed */
212 unsigned char *hiPtr;
214 int guard_failed = FALSE;
217 for (idx = 0; idx < LOW_GUARD_SIZE; idx++) {
218 byte = *(memHeaderP->low_guard + idx);
219 if (byte != GUARD_VALUE) {
223 fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", idx, byte,
224 (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */
228 TclDumpMemoryInfo (stderr);
229 fprintf(stderr, "low guard failed at %lx, %s %d\n",
230 (long unsigned int) memHeaderP->body, file, line);
231 fflush(stderr); /* In case name pointer is bad. */
232 fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length,
233 memHeaderP->file, memHeaderP->line);
234 panic ("Memory validation failure");
237 hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
238 for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) {
239 byte = *(hiPtr + idx);
240 if (byte != GUARD_VALUE) {
244 fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", idx, byte,
245 (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */
250 TclDumpMemoryInfo (stderr);
251 fprintf(stderr, "high guard failed at %lx, %s %d\n",
252 (long unsigned int) memHeaderP->body, file, line);
253 fflush(stderr); /* In case name pointer is bad. */
254 fprintf(stderr, "%ld bytes allocated at (%s %d)\n",
255 memHeaderP->length, memHeaderP->file,
257 panic("Memory validation failure");
261 memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE);
262 memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE);
268 *----------------------------------------------------------------------
270 * Tcl_ValidateAllMemory --
272 * Validate memory guard regions for all allocated memory.
278 * Displays memory validation information to stderr.
280 *----------------------------------------------------------------------
283 Tcl_ValidateAllMemory (file, line)
284 CONST char *file; /* File from which Tcl_ValidateAllMemory was called */
285 int line; /* Line number of call to Tcl_ValidateAllMemory */
287 struct mem_header *memScanP;
292 Tcl_MutexLock(ckallocMutexPtr);
293 for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
294 ValidateMemory(memScanP, file, line, FALSE);
296 Tcl_MutexUnlock(ckallocMutexPtr);
300 *----------------------------------------------------------------------
302 * Tcl_DumpActiveMemory --
304 * Displays all allocated memory to a file; if no filename is given,
305 * information will be written to stderr.
308 * Return TCL_ERROR if an error accessing the file occurs, `errno'
309 * will have the file error number left in it.
310 *----------------------------------------------------------------------
313 Tcl_DumpActiveMemory (fileName)
314 CONST char *fileName; /* Name of the file to write info to */
317 struct mem_header *memScanP;
320 if (fileName == NULL) {
323 fileP = fopen(fileName, "w");
329 Tcl_MutexLock(ckallocMutexPtr);
330 for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
331 address = &memScanP->body [0];
332 fprintf(fileP, "%8lx - %8lx %7ld @ %s %d %s",
333 (long unsigned int) address,
334 (long unsigned int) address + memScanP->length - 1,
335 memScanP->length, memScanP->file, memScanP->line,
336 (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string);
337 (void) fputc('\n', fileP);
339 Tcl_MutexUnlock(ckallocMutexPtr);
341 if (fileP != stderr) {
348 *----------------------------------------------------------------------
350 * Tcl_DbCkalloc - debugging ckalloc
352 * Allocate the requested amount of space plus some extra for
353 * guard bands at both ends of the request, plus a size, panicing
354 * if there isn't enough space, then write in the guard bands
355 * and return the address of the space in the middle that the
358 * The second and third arguments are file and line, these contain
359 * the filename and line number corresponding to the caller.
360 * These are sent by the ckalloc macro; it uses the preprocessor
361 * autodefines __FILE__ and __LINE__.
363 *----------------------------------------------------------------------
366 Tcl_DbCkalloc(size, file, line)
371 struct mem_header *result;
374 Tcl_ValidateAllMemory (file, line);
376 result = (struct mem_header *) TclpAlloc((unsigned)size +
377 sizeof(struct mem_header) + HIGH_GUARD_SIZE);
378 if (result == NULL) {
380 TclDumpMemoryInfo(stderr);
381 panic("unable to alloc %ud bytes, %s line %d", size, file, line);
385 * Fill in guard zones and size. Also initialize the contents of
386 * the block with bogus bytes to detect uses of initialized data.
387 * Link into allocated list.
389 if (init_malloced_bodies) {
390 memset ((VOID *) result, GUARD_VALUE,
391 size + sizeof(struct mem_header) + HIGH_GUARD_SIZE);
393 memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE);
394 memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE);
399 Tcl_MutexLock(ckallocMutexPtr);
400 result->length = size;
401 result->tagPtr = curTagPtr;
402 if (curTagPtr != NULL) {
403 curTagPtr->refCount++;
407 result->flink = allocHead;
408 result->blink = NULL;
410 if (allocHead != NULL)
411 allocHead->blink = result;
415 if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
416 (void) fflush(stdout);
417 fprintf(stderr, "reached malloc trace enable point (%d)\n",
420 alloc_tracing = TRUE;
421 trace_on_at_malloc = 0;
425 fprintf(stderr,"ckalloc %lx %ud %s %d\n",
426 (long unsigned int) result->body, size, file, line);
428 if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
430 (void) fflush(stdout);
431 fprintf(stderr,"reached malloc break limit (%d)\n",
433 fprintf(stderr, "program will now enter C debugger\n");
434 (void) fflush(stderr);
438 current_malloc_packets++;
439 if (current_malloc_packets > maximum_malloc_packets)
440 maximum_malloc_packets = current_malloc_packets;
441 current_bytes_malloced += size;
442 if (current_bytes_malloced > maximum_bytes_malloced)
443 maximum_bytes_malloced = current_bytes_malloced;
445 Tcl_MutexUnlock(ckallocMutexPtr);
451 Tcl_AttemptDbCkalloc(size, file, line)
456 struct mem_header *result;
459 Tcl_ValidateAllMemory (file, line);
461 result = (struct mem_header *) TclpAlloc((unsigned)size +
462 sizeof(struct mem_header) + HIGH_GUARD_SIZE);
463 if (result == NULL) {
465 TclDumpMemoryInfo(stderr);
470 * Fill in guard zones and size. Also initialize the contents of
471 * the block with bogus bytes to detect uses of initialized data.
472 * Link into allocated list.
474 if (init_malloced_bodies) {
475 memset ((VOID *) result, GUARD_VALUE,
476 size + sizeof(struct mem_header) + HIGH_GUARD_SIZE);
478 memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE);
479 memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE);
484 Tcl_MutexLock(ckallocMutexPtr);
485 result->length = size;
486 result->tagPtr = curTagPtr;
487 if (curTagPtr != NULL) {
488 curTagPtr->refCount++;
492 result->flink = allocHead;
493 result->blink = NULL;
495 if (allocHead != NULL)
496 allocHead->blink = result;
500 if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
501 (void) fflush(stdout);
502 fprintf(stderr, "reached malloc trace enable point (%d)\n",
505 alloc_tracing = TRUE;
506 trace_on_at_malloc = 0;
510 fprintf(stderr,"ckalloc %lx %ud %s %d\n",
511 (long unsigned int) result->body, size, file, line);
513 if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
515 (void) fflush(stdout);
516 fprintf(stderr,"reached malloc break limit (%d)\n",
518 fprintf(stderr, "program will now enter C debugger\n");
519 (void) fflush(stderr);
523 current_malloc_packets++;
524 if (current_malloc_packets > maximum_malloc_packets)
525 maximum_malloc_packets = current_malloc_packets;
526 current_bytes_malloced += size;
527 if (current_bytes_malloced > maximum_bytes_malloced)
528 maximum_bytes_malloced = current_bytes_malloced;
530 Tcl_MutexUnlock(ckallocMutexPtr);
537 *----------------------------------------------------------------------
539 * Tcl_DbCkfree - debugging ckfree
541 * Verify that the low and high guards are intact, and if so
542 * then free the buffer else panic.
544 * The guards are erased after being checked to catch duplicate
547 * The second and third arguments are file and line, these contain
548 * the filename and line number corresponding to the caller.
549 * These are sent by the ckfree macro; it uses the preprocessor
550 * autodefines __FILE__ and __LINE__.
552 *----------------------------------------------------------------------
556 Tcl_DbCkfree(ptr, file, line)
561 struct mem_header *memp;
568 * The following cast is *very* tricky. Must convert the pointer
569 * to an integer before doing arithmetic on it, because otherwise
570 * the arithmetic will be done differently (and incorrectly) on
571 * word-addressed machines such as Crays (will subtract only bytes,
572 * even though BODY_OFFSET is in words on these machines).
575 memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
578 fprintf(stderr, "ckfree %lx %ld %s %d\n",
579 (long unsigned int) memp->body, memp->length, file, line);
582 if (validate_memory) {
583 Tcl_ValidateAllMemory(file, line);
586 Tcl_MutexLock(ckallocMutexPtr);
587 ValidateMemory(memp, file, line, TRUE);
588 if (init_malloced_bodies) {
589 memset((VOID *) ptr, GUARD_VALUE, (size_t) memp->length);
593 current_malloc_packets--;
594 current_bytes_malloced -= memp->length;
596 if (memp->tagPtr != NULL) {
597 memp->tagPtr->refCount--;
598 if ((memp->tagPtr->refCount == 0) && (curTagPtr != memp->tagPtr)) {
599 TclpFree((char *) memp->tagPtr);
604 * Delink from allocated list
606 if (memp->flink != NULL)
607 memp->flink->blink = memp->blink;
608 if (memp->blink != NULL)
609 memp->blink->flink = memp->flink;
610 if (allocHead == memp)
611 allocHead = memp->flink;
612 TclpFree((char *) memp);
613 Tcl_MutexUnlock(ckallocMutexPtr);
619 *--------------------------------------------------------------------
621 * Tcl_DbCkrealloc - debugging ckrealloc
623 * Reallocate a chunk of memory by allocating a new one of the
624 * right size, copying the old data to the new location, and then
625 * freeing the old memory space, using all the memory checking
626 * features of this package.
628 *--------------------------------------------------------------------
631 Tcl_DbCkrealloc(ptr, size, file, line)
638 unsigned int copySize;
639 struct mem_header *memp;
642 return Tcl_DbCkalloc(size, file, line);
646 * See comment from Tcl_DbCkfree before you change the following
650 memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
653 if (copySize > (unsigned int) memp->length) {
654 copySize = memp->length;
656 new = Tcl_DbCkalloc(size, file, line);
657 memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize);
658 Tcl_DbCkfree(ptr, file, line);
663 Tcl_AttemptDbCkrealloc(ptr, size, file, line)
670 unsigned int copySize;
671 struct mem_header *memp;
674 return Tcl_AttemptDbCkalloc(size, file, line);
678 * See comment from Tcl_DbCkfree before you change the following
682 memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
685 if (copySize > (unsigned int) memp->length) {
686 copySize = memp->length;
688 new = Tcl_AttemptDbCkalloc(size, file, line);
692 memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize);
693 Tcl_DbCkfree(ptr, file, line);
699 *----------------------------------------------------------------------
701 * Tcl_Alloc, et al. --
703 * These functions are defined in terms of the debugging versions
704 * when TCL_MEM_DEBUG is set.
707 * Same as the debug versions.
710 * Same as the debug versions.
712 *----------------------------------------------------------------------
718 #undef Tcl_AttemptAlloc
719 #undef Tcl_AttemptRealloc
725 return Tcl_DbCkalloc(size, "unknown", 0);
729 Tcl_AttemptAlloc(size)
732 return Tcl_AttemptDbCkalloc(size, "unknown", 0);
739 Tcl_DbCkfree(ptr, "unknown", 0);
743 Tcl_Realloc(ptr, size)
747 return Tcl_DbCkrealloc(ptr, size, "unknown", 0);
750 Tcl_AttemptRealloc(ptr, size)
754 return Tcl_AttemptDbCkrealloc(ptr, size, "unknown", 0);
758 *----------------------------------------------------------------------
761 * Implements the Tcl "memory" command, which provides Tcl-level
762 * control of Tcl memory debugging information.
763 * memory active $file
764 * memory break_on_malloc $count
767 * memory onexit $file
769 * memory trace on|off
770 * memory trace_on_at_malloc $count
771 * memory validate on|off
774 * Standard TCL results.
776 *----------------------------------------------------------------------
780 MemoryCmd (clientData, interp, argc, argv)
781 ClientData clientData;
786 CONST char *fileName;
791 Tcl_AppendResult(interp, "wrong # args: should be \"",
792 argv[0], " option [args..]\"", (char *) NULL);
796 if ((strcmp(argv[1],"active") == 0) || (strcmp(argv[1],"display") == 0)) {
798 Tcl_AppendResult(interp, "wrong # args: should be \"",
799 argv[0], " ", argv[1], " file\"", (char *) NULL);
802 fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);
803 if (fileName == NULL) {
806 result = Tcl_DumpActiveMemory (fileName);
807 Tcl_DStringFree(&buffer);
808 if (result != TCL_OK) {
809 Tcl_AppendResult(interp, "error accessing ", argv[2],
815 if (strcmp(argv[1],"break_on_malloc") == 0) {
819 if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) {
824 if (strcmp(argv[1],"info") == 0) {
826 sprintf(buf, "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n",
827 "total mallocs", total_mallocs, "total frees", total_frees,
828 "current packets allocated", current_malloc_packets,
829 "current bytes allocated", current_bytes_malloced,
830 "maximum packets allocated", maximum_malloc_packets,
831 "maximum bytes allocated", maximum_bytes_malloced);
832 Tcl_SetResult(interp, buf, TCL_VOLATILE);
835 if (strcmp(argv[1],"init") == 0) {
839 init_malloced_bodies = (strcmp(argv[2],"on") == 0);
842 if (strcmp(argv[1],"onexit") == 0) {
844 Tcl_AppendResult(interp, "wrong # args: should be \"",
845 argv[0], " onexit file\"", (char *) NULL);
848 fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);
849 if (fileName == NULL) {
852 onExitMemDumpFileName = dumpFile;
853 strcpy(onExitMemDumpFileName,fileName);
854 Tcl_DStringFree(&buffer);
857 if (strcmp(argv[1],"tag") == 0) {
859 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
860 " tag string\"", (char *) NULL);
863 if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) {
864 TclpFree((char *) curTagPtr);
866 curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(strlen(argv[2])));
867 curTagPtr->refCount = 0;
868 strcpy(curTagPtr->string, argv[2]);
871 if (strcmp(argv[1],"trace") == 0) {
875 alloc_tracing = (strcmp(argv[2],"on") == 0);
879 if (strcmp(argv[1],"trace_on_at_malloc") == 0) {
883 if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) {
888 if (strcmp(argv[1],"validate") == 0) {
892 validate_memory = (strcmp(argv[2],"on") == 0);
896 Tcl_AppendResult(interp, "bad option \"", argv[1],
897 "\": should be active, break_on_malloc, info, init, onexit, ",
898 "tag, trace, trace_on_at_malloc, or validate", (char *) NULL);
902 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
903 " ", argv[1], " count\"", (char *) NULL);
907 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
908 " ", argv[1], " on|off\"", (char *) NULL);
913 *----------------------------------------------------------------------
917 * This is the command procedure for the "checkmem" command, which
918 * causes the application to exit after printing information about
919 * memory usage to the file passed to this command as its first
923 * Returns a standard Tcl completion code.
928 *----------------------------------------------------------------------
932 CheckmemCmd(clientData, interp, argc, argv)
933 ClientData clientData; /* Not used. */
934 Tcl_Interp *interp; /* Interpreter for evaluation. */
935 int argc; /* Number of arguments. */
936 CONST char *argv[]; /* String values of arguments. */
939 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
940 " fileName\"", (char *) NULL);
943 tclMemDumpFileName = dumpFile;
944 strcpy(tclMemDumpFileName, argv[1]);
949 *----------------------------------------------------------------------
953 * Create the "memory" and "checkmem" commands in the given
960 * New commands are added to the interpreter.
962 *----------------------------------------------------------------------
966 Tcl_InitMemory(interp)
967 Tcl_Interp *interp; /* Interpreter in which commands should be added */
970 Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData) NULL,
971 (Tcl_CmdDeleteProc *) NULL);
972 Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
973 (Tcl_CmdDeleteProc *) NULL);
977 #else /* TCL_MEM_DEBUG */
979 /* This is the !TCL_MEM_DEBUG case */
981 #undef Tcl_InitMemory
982 #undef Tcl_DumpActiveMemory
983 #undef Tcl_ValidateAllMemory
987 *----------------------------------------------------------------------
990 * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does check
991 * that memory was actually allocated.
993 *----------------------------------------------------------------------
1002 result = TclpAlloc(size);
1004 * Most systems will not alloc(0), instead bumping it to one so
1005 * that NULL isn't returned. Some systems (AIX, Tru64) will alloc(0)
1006 * by returning NULL, so we have to check that the NULL we get is
1007 * not in response to alloc(0).
1009 * The ANSI spec actually says that systems either return NULL *or*
1010 * a special pointer on failure, but we only check for NULL
1012 if ((result == NULL) && size) {
1013 panic("unable to alloc %ud bytes", size);
1019 Tcl_DbCkalloc(size, file, line)
1026 result = (char *) TclpAlloc(size);
1028 if ((result == NULL) && size) {
1030 panic("unable to alloc %ud bytes, %s line %d", size, file, line);
1036 *----------------------------------------------------------------------
1038 * Tcl_AttemptAlloc --
1039 * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does not
1040 * check that memory was actually allocated.
1042 *----------------------------------------------------------------------
1046 Tcl_AttemptAlloc (size)
1051 result = TclpAlloc(size);
1056 Tcl_AttemptDbCkalloc(size, file, line)
1063 result = (char *) TclpAlloc(size);
1069 *----------------------------------------------------------------------
1072 * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does
1073 * check that memory was actually allocated.
1075 *----------------------------------------------------------------------
1079 Tcl_Realloc(ptr, size)
1085 result = TclpRealloc(ptr, size);
1087 if ((result == NULL) && size) {
1088 panic("unable to realloc %ud bytes", size);
1094 Tcl_DbCkrealloc(ptr, size, file, line)
1102 result = (char *) TclpRealloc(ptr, size);
1104 if ((result == NULL) && size) {
1106 panic("unable to realloc %ud bytes, %s line %d", size, file, line);
1112 *----------------------------------------------------------------------
1114 * Tcl_AttemptRealloc --
1115 * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does
1116 * not check that memory was actually allocated.
1118 *----------------------------------------------------------------------
1122 Tcl_AttemptRealloc(ptr, size)
1128 result = TclpRealloc(ptr, size);
1133 Tcl_AttemptDbCkrealloc(ptr, size, file, line)
1141 result = (char *) TclpRealloc(ptr, size);
1146 *----------------------------------------------------------------------
1149 * Interface to TclpFree when TCL_MEM_DEBUG is disabled. Done here
1150 * rather in the macro to keep some modules from being compiled with
1151 * TCL_MEM_DEBUG enabled and some with it disabled.
1153 *----------------------------------------------------------------------
1164 Tcl_DbCkfree(ptr, file, line)
1174 *----------------------------------------------------------------------
1177 * Dummy initialization for memory command, which is only available
1178 * if TCL_MEM_DEBUG is on.
1180 *----------------------------------------------------------------------
1184 Tcl_InitMemory(interp)
1190 Tcl_DumpActiveMemory(fileName)
1191 CONST char *fileName;
1197 Tcl_ValidateAllMemory(file, line)
1204 TclDumpMemoryInfo(outFile)
1209 #endif /* TCL_MEM_DEBUG */
1212 *---------------------------------------------------------------------------
1214 * TclFinalizeMemorySubsystem --
1216 * This procedure is called to finalize all the structures that
1217 * are used by the memory allocator on a per-process basis.
1223 * This subsystem is self-initializing, since memory can be
1224 * allocated before Tcl is formally initialized. After this call,
1225 * this subsystem has been reset to its initial state and is
1228 *---------------------------------------------------------------------------
1232 TclFinalizeMemorySubsystem()
1234 #ifdef TCL_MEM_DEBUG
1235 if (tclMemDumpFileName != NULL) {
1236 Tcl_DumpActiveMemory(tclMemDumpFileName);
1237 } else if (onExitMemDumpFileName != NULL) {
1238 Tcl_DumpActiveMemory(onExitMemDumpFileName);
1240 Tcl_MutexLock(ckallocMutexPtr);
1241 if (curTagPtr != NULL) {
1242 TclpFree((char *) curTagPtr);
1246 Tcl_MutexUnlock(ckallocMutexPtr);
1250 TclFinalizeAllocSubsystem();