📄 tclckalloc.c
字号:
#ifndef EXCLUDE_TCL/* * tclCkalloc.c -- * Interface to malloc and free that provides support for debugging problems * involving overwritten, double freeing memory and loss of memory. * * Copyright 1991 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * * This code contributed by Karl Lehenbauer and Mark Diekhans * */#include "tclInt.h"#define FALSE 0#define TRUE 1/* Tcl private heap pool which must be located continuously to form single large one *//*************************************************************************************/static unsigned char heapPool_0[16*1024]; /* Less than 32KB to avoid compiler error */static unsigned char heapPool_1[16*1024]; /* Less than 32KB to avoid compiler error */static unsigned char heapPool_2[16*1024]; /* Less than 32KB to avoid compiler error */static unsigned char heapPool_3[16*1024]; /* Less than 32KB to avoid compiler error *//*************************************************************************************/static heapMgt_t *memHeap = NULL; /* Tcl specific heap management control structure */#ifdef TCL_MEM_DEBUG#ifndef TCL_GENERIC_ONLY#include "tclUnix.h"#endif#define GUARD_SIZE 8struct mem_header { long length; char *file; int line; struct mem_header *flink; struct mem_header *blink; unsigned char low_guard[GUARD_SIZE]; char body[1];};static struct mem_header *allocHead = NULL; /* List of allocated structures */#define GUARD_VALUE 0341/* static char high_guard[] = {0x89, 0xab, 0xcd, 0xef}; */static long total_mallocs = 0;static long total_frees = 0;static long current_bytes_malloced = 0;static long maximum_bytes_malloced = 0;static long current_malloc_packets = 0;static long maximum_malloc_packets = 0;static long break_on_malloc = 0;static long trace_on_at_malloc = 0;static int alloc_tracing = FALSE;static int init_malloced_bodies = FALSE;#ifdef MEM_VALIDATEstatic int validate_memory = TRUE;#elsestatic int validate_memory = FALSE;#endif/* *---------------------------------------------------------------------- * * dump_memory_info -- * Display the global memory management statistics. * *---------------------------------------------------------------------- */static voiddump_memory_info(void){ tracef("total mallocs %10ld\n", total_mallocs); tracef("total frees %10ld\n", total_frees); tracef("current packets allocated %10ld\n", current_malloc_packets); tracef("current bytes allocated %10ld\n", current_bytes_malloced); tracef("maximum packets allocated %10ld\n", maximum_malloc_packets); tracef("maximum bytes allocated %10ld\n", maximum_bytes_malloced);}/* *---------------------------------------------------------------------- * * ValidateMemory -- * Procedure to validate allocted memory guard zones. * *---------------------------------------------------------------------- */static voidValidateMemory (memHeaderP, file, line, nukeGuards) struct mem_header *memHeaderP; char *file; int line; int nukeGuards;{ unsigned char *hiPtr; int idx; int guard_failed = FALSE; int byte; for (idx = 0; idx < GUARD_SIZE; idx++) { byte = *(memHeaderP->low_guard + idx); if (byte != GUARD_VALUE) { guard_failed = TRUE; byte &= 0xff; tracef("low guard byte %d is 0x%x \t%c\n", idx, byte, (isprint(byte) ? byte : ' ')); } } if (guard_failed) { dump_memory_info (); tracef ("low guard failed at %lx, %s %d\n", memHeaderP->body, file, line); tracef ("%d bytes allocated at (%s %d)\n", memHeaderP->length, memHeaderP->file, memHeaderP->line); panic ("Memory validation failure"); } hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length; for (idx = 0; idx < GUARD_SIZE; idx++) { byte = *(hiPtr + idx); if (byte != GUARD_VALUE) { guard_failed = TRUE; byte &= 0xff; tracef("hi guard byte %d is 0x%x \t%c\n", idx, byte, (isprint(byte) ? byte : ' ')); } } if (guard_failed) { dump_memory_info (); tracef ("high guard failed at %lx, %s %d\n", memHeaderP->body, file, line); tracef ("%d bytes allocated at (%s %d)\n", memHeaderP->length, memHeaderP->file, memHeaderP->line); panic ("Memory validation failure"); } if (nukeGuards) { memset ((char *) memHeaderP->low_guard, 0, GUARD_SIZE); memset ((char *) hiPtr, 0, GUARD_SIZE); }}/* *---------------------------------------------------------------------- * * Tcl_ValidateAllMemory -- * Validates guard regions for all allocated memory. * *---------------------------------------------------------------------- */voidTcl_ValidateAllMemory (file, line) char *file; int line;{ struct mem_header *memScanP; for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) ValidateMemory (memScanP, file, line, FALSE);}/* *---------------------------------------------------------------------- * * Tcl_DumpActiveMemory -- * Displays all allocated memory to stderr. * * Results: * Return TCL_ERROR if an error accessing the file occures, `errno' * will have the file error number left in it. *---------------------------------------------------------------------- */intTcl_DumpActiveMemory (fileName) char *fileName;{ struct mem_header *memScanP; char *address; for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { address = &memScanP->body [0]; tracef ("%8lx - %8lx %7d @ %s %d", address, address + memScanP->length - 1, memScanP->length, memScanP->file, memScanP->line); if (strcmp(memScanP->file, "tclHash.c") == 0 && memScanP->line == 518){ tracef("\t|%s|", ((Tcl_HashEntry *) address)->key.string); } tracef("\n"); } return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_DbCkalloc - debugging ckalloc * * Allocate the requested amount of space plus some extra for * guard bands at both ends of the request, plus a size, panicing * if there isn't enough space, then write in the guard bands * and return the address of the space in the middle that the * user asked for. * * The second and third arguments are file and line, these contain * the filename and line number corresponding to the caller. * These are sent by the ckalloc macro; it uses the preprocessor * autodefines __FILE__ and __LINE__. * *---------------------------------------------------------------------- */char *Tcl_DbCkalloc(size, file, line) unsigned int size; char *file; int line;{ struct mem_header *result; if (validate_memory) Tcl_ValidateAllMemory (file, line); result = (struct mem_header *)Tcl_Malloc((unsigned)size + sizeof(struct mem_header) + GUARD_SIZE); if (result == NULL) { dump_memory_info(); panic("unable to alloc %d bytes, %s line %d", size, file, line); } /* * Fill in guard zones and size. Link into allocated list. */ result->length = size; result->file = file; result->line = line; memset ((char *) result->low_guard, GUARD_VALUE, GUARD_SIZE); memset (result->body + size, GUARD_VALUE, GUARD_SIZE); result->flink = allocHead; result->blink = NULL; if (allocHead != NULL) allocHead->blink = result; allocHead = result; total_mallocs++; if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { tracef("reached malloc trace enable point (%ld)\n", total_mallocs); alloc_tracing = TRUE; trace_on_at_malloc = 0; } if (alloc_tracing) tracef("ckalloc %lx %d %s %d\n", result->body, size, file, line); if (break_on_malloc && (total_mallocs >= break_on_malloc)) { break_on_malloc = 0; tracef("reached malloc break limit (%ld)\n", total_mallocs); panic("program will now enter C debugger\n"); } current_malloc_packets++; if (current_malloc_packets > maximum_malloc_packets) maximum_malloc_packets = current_malloc_packets; current_bytes_malloced += size; if (current_bytes_malloced > maximum_bytes_malloced) maximum_bytes_malloced = current_bytes_malloced; if (init_malloced_bodies) memset (result->body, 0xff, (int) size); return result->body;}/* *---------------------------------------------------------------------- * * Tcl_DbCkfree - debugging ckfree * * Verify that the low and high guards are intact, and if so * then free the buffer else panic. * * The guards are erased after being checked to catch duplicate * frees. * * The second and third arguments are file and line, these contain * the filename and line number corresponding to the caller. * These are sent by the ckfree macro; it uses the preprocessor * autodefines __FILE__ and __LINE__. * *---------------------------------------------------------------------- */intTcl_DbCkfree(ptr, file, line) char * ptr; char *file; int line;{ struct mem_header *memp = 0; /* Must be zero for size calc */ /* * Since header ptr is zero, body offset will be size */ memp = (struct mem_header *)(((char *) ptr) - (int)memp->body);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -