📄 tclalloc.c
字号:
/*
* 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
*
* $Id: tclalloc.c,v 1.1.1.1 2001/04/29 20:35:23 karll Exp $
*
*/
#include "tclInt.h"
#define FALSE 0
#define TRUE 1
#ifdef TCL_MEM_DEBUG
#ifndef TCL_GENERIC_ONLY
#include "tclEcos.h"
#endif
#define GUARD_SIZE 8
struct 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 int total_mallocs = 0;
static int total_frees = 0;
static long current_bytes_malloced = 0;
static long maximum_bytes_malloced = 0;
static int current_malloc_packets = 0;
static int maximum_malloc_packets = 0;
static int break_on_malloc = 0;
static int trace_on_at_malloc = 0;
static int alloc_tracing = FALSE;
static int init_malloced_bodies = FALSE;
#ifdef MEM_VALIDATE
int validate_memory = TRUE;
#else
int validate_memory = FALSE;
#endif
/*
*----------------------------------------------------------------------
*
* dump_memory_info --
* Display the global memory management statistics.
*
*----------------------------------------------------------------------
*/
static void
dump_memory_info(outFile)
FILE *outFile;
{
fprintf(outFile,"total mallocs %10d\n",
total_mallocs);
fprintf(outFile,"total frees %10d\n",
total_frees);
fprintf(outFile,"current packets allocated %10d\n",
current_malloc_packets);
fprintf(outFile,"current bytes allocated %10ld\n",
current_bytes_malloced);
fprintf(outFile,"maximum packets allocated %10d\n",
maximum_malloc_packets);
fprintf(outFile,"maximum bytes allocated %10ld\n",
maximum_bytes_malloced);
}
/*
*----------------------------------------------------------------------
*
* ValidateMemory --
* Procedure to validate allocted memory guard zones.
*
*----------------------------------------------------------------------
*/
static void
ValidateMemory (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;
fflush (stdout);
byte &= 0xff;
fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", idx, byte,
(isprint(byte) ? byte : ' '));
}
}
if (guard_failed) {
dump_memory_info (stderr);
fprintf (stderr, "low guard failed at %lx, %s %d\n",
memHeaderP->body, file, line);
fflush (stderr); /* In case name pointer is bad. */
fprintf (stderr, "%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;
fflush (stdout);
byte &= 0xff;
fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", idx, byte,
(isprint(byte) ? byte : ' '));
}
}
if (guard_failed) {
dump_memory_info (stderr);
fprintf (stderr, "high guard failed at %lx, %s %d\n",
memHeaderP->body, file, line);
fflush (stderr); /* In case name pointer is bad. */
fprintf (stderr, "%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.
*
*----------------------------------------------------------------------
*/
void
Tcl_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.
*----------------------------------------------------------------------
*/
int
Tcl_DumpActiveMemory (fileName)
char *fileName;
{
FILE *fileP;
struct mem_header *memScanP;
char *address;
fileP = fopen (fileName, "w");
if (fileP == NULL)
return TCL_ERROR;
for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
address = &memScanP->body [0];
fprintf (fileP, "%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 == 515){
fprintf(fileP, "\t|%s|", ((Tcl_HashEntry *) address)->key.string);
}
(void) fputc('\n', fileP);
}
fclose (fileP);
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 *)malloc((unsigned)size +
sizeof(struct mem_header) + GUARD_SIZE);
if (result == NULL) {
fflush(stdout);
dump_memory_info(stderr);
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)) {
(void) fflush(stdout);
fprintf(stderr, "reached malloc trace enable point (%d)\n",
total_mallocs);
fflush(stderr);
alloc_tracing = TRUE;
trace_on_at_malloc = 0;
}
if (alloc_tracing)
fprintf(stderr,"ckalloc %lx %d %s %d\n", result->body, size,
file, line);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -