Changeset adeddd8 in git for external/tcl/tclCkalloc.c
- Timestamp:
- May 29, 2019, 2:53:12 PM (5 years ago)
- Branches:
- ImprovedOutputFile, Timing, master
- Children:
- 969eb19
- Parents:
- e15936c
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
external/tcl/tclCkalloc.c
re15936c radeddd8 22 22 #define TRUE 1 23 23 24 #ifdef TCL_MEM_DEBUG25 26 /*27 * One of the following structures is allocated each time the28 * "memory tag" command is invoked, to hold the current tag.29 */30 31 typedef struct MemTag {32 int refCount; /* Number of mem_headers referencing33 * this tag. */34 char string[4]; /* Actual size of string will be as35 * large as needed for actual tag. This36 * must be the last field in the structure. */37 } MemTag;38 39 #define TAG_SIZE(bytesInString) ((unsigned) sizeof(MemTag) + bytesInString - 3)40 41 static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers42 * (set by "memory tag" command). */43 44 /*45 * One of the following structures is allocated just before each46 * dynamically allocated chunk of memory, both to record information47 * about the chunk and to help detect chunk under-runs.48 */49 50 #define LOW_GUARD_SIZE (8 + (32 - (sizeof(long) + sizeof(int)))%8)51 struct mem_header {52 struct mem_header *flink;53 struct mem_header *blink;54 MemTag *tagPtr; /* Tag from "memory tag" command; may be55 * NULL. */56 char *file;57 long length;58 int line;59 unsigned char low_guard[LOW_GUARD_SIZE];60 /* Aligns body on 8-byte boundary, plus61 * provides at least 8 additional guard bytes62 * to detect underruns. */63 char body[1]; /* First byte of client's space. Actual64 * size of this field will be larger than65 * one. */66 };67 68 static struct mem_header *allocHead = NULL; /* List of allocated structures */69 70 #define GUARD_VALUE 014171 72 /*73 * The following macro determines the amount of guard space *above* each74 * chunk of memory.75 */76 77 #define HIGH_GUARD_SIZE 878 79 /*80 * The following macro computes the offset of the "body" field within81 * mem_header. It is used to get back to the header pointer from the82 * body pointer that's used by clients.83 */84 85 #define BODY_OFFSET \86 ((unsigned long) (&((struct mem_header *) 0)->body))87 88 static int total_mallocs = 0;89 static int total_frees = 0;90 static int current_bytes_malloced = 0;91 static int maximum_bytes_malloced = 0;92 static int current_malloc_packets = 0;93 static int maximum_malloc_packets = 0;94 static int break_on_malloc = 0;95 static int trace_on_at_malloc = 0;96 static int alloc_tracing = FALSE;97 static int init_malloced_bodies = TRUE;98 #ifdef MEM_VALIDATE99 static int validate_memory = TRUE;100 #else101 static int validate_memory = FALSE;102 #endif103 104 /*105 * Prototypes for procedures defined in this file:106 */107 108 static int MemoryCmd _ANSI_ARGS_((ClientData clientData,109 Tcl_Interp *interp, int argc, char **argv));110 static void ValidateMemory _ANSI_ARGS_((111 struct mem_header *memHeaderP, char *file,112 int line, int nukeGuards));113 114 115 /*116 *----------------------------------------------------------------------117 *118 * TclDumpMemoryInfo --119 * Display the global memory management statistics.120 *121 *----------------------------------------------------------------------122 */123 void124 TclDumpMemoryInfo(outFile)125 FILE *outFile;126 {127 fprintf(outFile,"total mallocs %10d\n",128 total_mallocs);129 fprintf(outFile,"total frees %10d\n",130 total_frees);131 fprintf(outFile,"current packets allocated %10d\n",132 current_malloc_packets);133 fprintf(outFile,"current bytes allocated %10d\n",134 current_bytes_malloced);135 fprintf(outFile,"maximum packets allocated %10d\n",136 maximum_malloc_packets);137 fprintf(outFile,"maximum bytes allocated %10d\n",138 maximum_bytes_malloced);139 }140 141 142 /*143 *----------------------------------------------------------------------144 *145 * ValidateMemory --146 * Procedure to validate allocted memory guard zones.147 *148 *----------------------------------------------------------------------149 */150 static void151 ValidateMemory(memHeaderP, file, line, nukeGuards)152 struct mem_header *memHeaderP;153 char *file;154 int line;155 int nukeGuards;156 {157 unsigned char *hiPtr;158 int idx;159 int guard_failed = FALSE;160 int byte;161 162 for (idx = 0; idx < LOW_GUARD_SIZE; idx++) {163 byte = *(memHeaderP->low_guard + idx);164 if (byte != GUARD_VALUE) {165 guard_failed = TRUE;166 fflush(stdout);167 byte &= 0xff;168 fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", idx, byte,169 (isprint(UCHAR(byte)) ? byte : ' '));170 }171 }172 if (guard_failed) {173 TclDumpMemoryInfo (stderr);174 fprintf(stderr, "low guard failed at %lx, %s %d\n",175 (long unsigned int) memHeaderP->body, file, line);176 fflush(stderr); /* In case name pointer is bad. */177 fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length,178 memHeaderP->file, memHeaderP->line);179 panic ("Memory validation failure");180 }181 182 hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;183 for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) {184 byte = *(hiPtr + idx);185 if (byte != GUARD_VALUE) {186 guard_failed = TRUE;187 fflush (stdout);188 byte &= 0xff;189 fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", idx, byte,190 (isprint(UCHAR(byte)) ? byte : ' '));191 }192 }193 194 if (guard_failed) {195 TclDumpMemoryInfo (stderr);196 fprintf(stderr, "high guard failed at %lx, %s %d\n",197 (long unsigned int) memHeaderP->body, file, line);198 fflush(stderr); /* In case name pointer is bad. */199 fprintf(stderr, "%ld bytes allocated at (%s %d)\n",200 memHeaderP->length, memHeaderP->file,201 memHeaderP->line);202 panic("Memory validation failure");203 }204 205 if (nukeGuards) {206 memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE);207 memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE);208 }209 210 }211 212 213 /*214 *----------------------------------------------------------------------215 *216 * Tcl_ValidateAllMemory --217 * Validates guard regions for all allocated memory.218 *219 *----------------------------------------------------------------------220 */221 void222 Tcl_ValidateAllMemory (file, line)223 char *file;224 int line;225 {226 struct mem_header *memScanP;227 228 for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink)229 ValidateMemory(memScanP, file, line, FALSE);230 231 }232 233 234 /*235 *----------------------------------------------------------------------236 *237 * Tcl_DumpActiveMemory --238 * Displays all allocated memory to stderr.239 *240 * Results:241 * Return TCL_ERROR if an error accessing the file occures, `errno'242 * will have the file error number left in it.243 *----------------------------------------------------------------------244 */245 int246 Tcl_DumpActiveMemory (fileName)247 char *fileName;248 {249 FILE *fileP;250 struct mem_header *memScanP;251 char *address;252 253 fileP = fopen(fileName, "w");254 if (fileP == NULL)255 return TCL_ERROR;256 257 for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {258 address = &memScanP->body [0];259 fprintf(fileP, "%8lx - %8lx %7ld @ %s %d %s",260 (long unsigned int) address,261 (long unsigned int) address + memScanP->length - 1,262 memScanP->length, memScanP->file, memScanP->line,263 (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string);264 (void) fputc('\n', fileP);265 }266 fclose (fileP);267 return TCL_OK;268 }269 270 271 /*272 *----------------------------------------------------------------------273 *274 * Tcl_DbCkalloc - debugging ckalloc275 *276 * Allocate the requested amount of space plus some extra for277 * guard bands at both ends of the request, plus a size, panicing278 * if there isn't enough space, then write in the guard bands279 * and return the address of the space in the middle that the280 * user asked for.281 *282 * The second and third arguments are file and line, these contain283 * the filename and line number corresponding to the caller.284 * These are sent by the ckalloc macro; it uses the preprocessor285 * autodefines __FILE__ and __LINE__.286 *287 *----------------------------------------------------------------------288 */289 char *290 Tcl_DbCkalloc(size, file, line)291 unsigned int size;292 char *file;293 int line;294 {295 struct mem_header *result;296 297 if (validate_memory)298 Tcl_ValidateAllMemory (file, line);299 300 result = (struct mem_header *) TclpAlloc((unsigned)size +301 sizeof(struct mem_header) + HIGH_GUARD_SIZE);302 if (result == NULL) {303 fflush(stdout);304 TclDumpMemoryInfo(stderr);305 panic("unable to alloc %d bytes, %s line %d", size, file,306 line);307 }308 309 /*310 * Fill in guard zones and size. Also initialize the contents of311 * the block with bogus bytes to detect uses of initialized data.312 * Link into allocated list.313 */314 if (init_malloced_bodies) {315 memset ((VOID *) result, GUARD_VALUE,316 size + sizeof(struct mem_header) + HIGH_GUARD_SIZE);317 } else {318 memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE);319 memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE);320 }321 result->length = size;322 result->tagPtr = curTagPtr;323 if (curTagPtr != NULL) {324 curTagPtr->refCount++;325 }326 result->file = file;327 result->line = line;328 result->flink = allocHead;329 result->blink = NULL;330 if (allocHead != NULL)331 allocHead->blink = result;332 allocHead = result;333 334 total_mallocs++;335 if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {336 (void) fflush(stdout);337 fprintf(stderr, "reached malloc trace enable point (%d)\n",338 total_mallocs);339 fflush(stderr);340 alloc_tracing = TRUE;341 trace_on_at_malloc = 0;342 }343 344 if (alloc_tracing)345 fprintf(stderr,"ckalloc %lx %d %s %d\n",346 (long unsigned int) result->body, size, file, line);347 348 if (break_on_malloc && (total_mallocs >= break_on_malloc)) {349 break_on_malloc = 0;350 (void) fflush(stdout);351 fprintf(stderr,"reached malloc break limit (%d)\n",352 total_mallocs);353 fprintf(stderr, "program will now enter C debugger\n");354 (void) fflush(stderr);355 abort();356 }357 358 current_malloc_packets++;359 if (current_malloc_packets > maximum_malloc_packets)360 maximum_malloc_packets = current_malloc_packets;361 current_bytes_malloced += size;362 if (current_bytes_malloced > maximum_bytes_malloced)363 maximum_bytes_malloced = current_bytes_malloced;364 365 return result->body;366 }367 368 369 /*370 *----------------------------------------------------------------------371 *372 * Tcl_DbCkfree - debugging ckfree373 *374 * Verify that the low and high guards are intact, and if so375 * then free the buffer else panic.376 *377 * The guards are erased after being checked to catch duplicate378 * frees.379 *380 * The second and third arguments are file and line, these contain381 * the filename and line number corresponding to the caller.382 * These are sent by the ckfree macro; it uses the preprocessor383 * autodefines __FILE__ and __LINE__.384 *385 *----------------------------------------------------------------------386 */387 388 int389 Tcl_DbCkfree(ptr, file, line)390 char * ptr;391 char *file;392 int line;393 {394 /*395 * The following cast is *very* tricky. Must convert the pointer396 * to an integer before doing arithmetic on it, because otherwise397 * the arithmetic will be done differently (and incorrectly) on398 * word-addressed machines such as Crays (will subtract only bytes,399 * even though BODY_OFFSET is in words on these machines).400 */401 402 struct mem_header *memp = (struct mem_header *)403 (((unsigned long) ptr) - BODY_OFFSET);404 405 if (alloc_tracing)406 fprintf(stderr, "ckfree %lx %ld %s %d\n",407 (long unsigned int) memp->body, memp->length, file, line);408 409 if (validate_memory)410 Tcl_ValidateAllMemory(file, line);411 412 ValidateMemory(memp, file, line, TRUE);413 if (init_malloced_bodies) {414 memset((VOID *) ptr, GUARD_VALUE, (size_t) memp->length);415 }416 417 total_frees++;418 current_malloc_packets--;419 current_bytes_malloced -= memp->length;420 421 if (memp->tagPtr != NULL) {422 memp->tagPtr->refCount--;423 if ((memp->tagPtr->refCount == 0) && (curTagPtr != memp->tagPtr)) {424 TclpFree((char *) memp->tagPtr);425 }426 }427 428 /*429 * Delink from allocated list430 */431 if (memp->flink != NULL)432 memp->flink->blink = memp->blink;433 if (memp->blink != NULL)434 memp->blink->flink = memp->flink;435 if (allocHead == memp)436 allocHead = memp->flink;437 TclpFree((char *) memp);438 return 0;439 }440 441 442 /*443 *--------------------------------------------------------------------444 *445 * Tcl_DbCkrealloc - debugging ckrealloc446 *447 * Reallocate a chunk of memory by allocating a new one of the448 * right size, copying the old data to the new location, and then449 * freeing the old memory space, using all the memory checking450 * features of this package.451 *452 *--------------------------------------------------------------------453 */454 char *455 Tcl_DbCkrealloc(ptr, size, file, line)456 char *ptr;457 unsigned int size;458 char *file;459 int line;460 {461 char *new;462 unsigned int copySize;463 464 /*465 * See comment from Tcl_DbCkfree before you change the following466 * line.467 */468 469 struct mem_header *memp = (struct mem_header *)470 (((unsigned long) ptr) - BODY_OFFSET);471 472 copySize = size;473 if (copySize > (unsigned int) memp->length) {474 copySize = memp->length;475 }476 new = Tcl_DbCkalloc(size, file, line);477 memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize);478 Tcl_DbCkfree(ptr, file, line);479 return(new);480 }481 482 483 484 /*485 *----------------------------------------------------------------------486 *487 * Tcl_Alloc, et al. --488 *489 * These functions are defined in terms of the debugging versions490 * when TCL_MEM_DEBUG is set.491 *492 * Results:493 * Same as the debug versions.494 *495 * Side effects:496 * Same as the debug versions.497 *498 *----------------------------------------------------------------------499 */500 501 #undef Tcl_Alloc502 #undef Tcl_Free503 #undef Tcl_Realloc504 505 char *506 Tcl_Alloc(size)507 unsigned int size;508 {509 return Tcl_DbCkalloc(size, "unknown", 0);510 }511 512 void513 Tcl_Free(ptr)514 char *ptr;515 {516 Tcl_DbCkfree(ptr, "unknown", 0);517 }518 519 char *520 Tcl_Realloc(ptr, size)521 char *ptr;522 unsigned int size;523 {524 return Tcl_DbCkrealloc(ptr, size, "unknown", 0);525 }526 527 528 /*529 *----------------------------------------------------------------------530 *531 * MemoryCmd --532 * Implements the TCL memory command:533 * memory info534 * memory display535 * break_on_malloc count536 * trace_on_at_malloc count537 * trace on|off538 * validate on|off539 *540 * Results:541 * Standard TCL results.542 *543 *----------------------------------------------------------------------544 */545 /* ARGSUSED */546 static int547 MemoryCmd (clientData, interp, argc, argv)548 ClientData clientData;549 Tcl_Interp *interp;550 int argc;551 char **argv;552 {553 char *fileName;554 Tcl_DString buffer;555 int result;556 557 if (argc < 2) {558 Tcl_AppendResult(interp, "wrong # args: should be \"",559 argv[0], " option [args..]\"", (char *) NULL);560 return TCL_ERROR;561 }562 563 if (strcmp(argv[1],"active") == 0) {564 if (argc != 3) {565 Tcl_AppendResult(interp, "wrong # args: should be \"",566 argv[0], " active file\"", (char *) NULL);567 return TCL_ERROR;568 }569 fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);570 if (fileName == NULL) {571 return TCL_ERROR;572 }573 result = Tcl_DumpActiveMemory (fileName);574 Tcl_DStringFree(&buffer);575 if (result != TCL_OK) {576 Tcl_AppendResult(interp, "error accessing ", argv[2],577 (char *) NULL);578 return TCL_ERROR;579 }580 return TCL_OK;581 }582 if (strcmp(argv[1],"break_on_malloc") == 0) {583 if (argc != 3) {584 goto argError;585 }586 if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) {587 return TCL_ERROR;588 }589 return TCL_OK;590 }591 if (strcmp(argv[1],"info") == 0) {592 TclDumpMemoryInfo(stdout);593 return TCL_OK;594 }595 if (strcmp(argv[1],"init") == 0) {596 if (argc != 3) {597 goto bad_suboption;598 }599 init_malloced_bodies = (strcmp(argv[2],"on") == 0);600 return TCL_OK;601 }602 if (strcmp(argv[1],"tag") == 0) {603 if (argc != 3) {604 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],605 " tag string\"", (char *) NULL);606 return TCL_ERROR;607 }608 if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) {609 TclpFree((char *) curTagPtr);610 }611 curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(strlen(argv[2])));612 curTagPtr->refCount = 0;613 strcpy(curTagPtr->string, argv[2]);614 return TCL_OK;615 }616 if (strcmp(argv[1],"trace") == 0) {617 if (argc != 3) {618 goto bad_suboption;619 }620 alloc_tracing = (strcmp(argv[2],"on") == 0);621 return TCL_OK;622 }623 624 if (strcmp(argv[1],"trace_on_at_malloc") == 0) {625 if (argc != 3) {626 goto argError;627 }628 if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) {629 return TCL_ERROR;630 }631 return TCL_OK;632 }633 if (strcmp(argv[1],"validate") == 0) {634 if (argc != 3) {635 goto bad_suboption;636 }637 validate_memory = (strcmp(argv[2],"on") == 0);638 return TCL_OK;639 }640 641 Tcl_AppendResult(interp, "bad option \"", argv[1],642 "\": should be active, break_on_malloc, info, init, ",643 "tag, trace, trace_on_at_malloc, or validate", (char *) NULL);644 return TCL_ERROR;645 646 argError:647 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],648 " ", argv[1], " count\"", (char *) NULL);649 return TCL_ERROR;650 651 bad_suboption:652 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],653 " ", argv[1], " on|off\"", (char *) NULL);654 return TCL_ERROR;655 }656 657 658 /*659 *----------------------------------------------------------------------660 *661 * Tcl_InitMemory --662 * Initialize the memory command.663 *664 *----------------------------------------------------------------------665 */666 void667 Tcl_InitMemory(interp)668 Tcl_Interp *interp;669 {670 Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData) NULL,671 (Tcl_CmdDeleteProc *) NULL);672 }673 674 #else675 676 677 678 24 /* 679 25 *---------------------------------------------------------------------- 680 26 * 681 27 * Tcl_Alloc -- 682 * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does check683 * 28 * Interface to TclpAlloc. 29 * It does check that memory was actually allocated. 684 30 * 685 31 *---------------------------------------------------------------------- … … 722 68 * 723 69 * Tcl_Realloc -- 724 * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does725 * 70 * Interface to TclpRealloc. 71 * It does check that memory was actually allocated. 726 72 * 727 73 *---------------------------------------------------------------------- … … 765 111 * 766 112 * Tcl_Free -- 767 * Interface to TclpFree when TCL_MEM_DEBUG is disabled. Done here 768 * rather in the macro to keep some modules from being compiled with 769 * TCL_MEM_DEBUG enabled and some with it disabled. 113 * Interface to TclpFree. 770 114 * 771 115 *---------------------------------------------------------------------- … … 778 122 TclpFree(ptr); 779 123 } 780 781 int782 Tcl_DbCkfree(ptr, file, line)783 char * ptr;784 char *file;785 int line;786 {787 TclpFree(ptr);788 return 0;789 }790 791 792 /*793 *----------------------------------------------------------------------794 *795 * Tcl_InitMemory --796 * Dummy initialization for memory command, which is only available797 * if TCL_MEM_DEBUG is on.798 *799 *----------------------------------------------------------------------800 */801 /* ARGSUSED */802 void803 Tcl_InitMemory(interp)804 Tcl_Interp *interp;805 {806 }807 808 #undef Tcl_DumpActiveMemory809 #undef Tcl_ValidateAllMemory810 811 extern int Tcl_DumpActiveMemory _ANSI_ARGS_((char *fileName));812 extern void Tcl_ValidateAllMemory _ANSI_ARGS_((char *file,813 int line));814 815 int816 Tcl_DumpActiveMemory(fileName)817 char *fileName;818 {819 return TCL_OK;820 }821 822 void823 Tcl_ValidateAllMemory(file, line)824 char *file;825 int line;826 {827 }828 829 #endif
Note:
See TracChangeset
for help on using the changeset viewer.