os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclCkalloc.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclCkalloc.c --
sl@0
     3
 *
sl@0
     4
 *    Interface to malloc and free that provides support for debugging problems
sl@0
     5
 *    involving overwritten, double freeing memory and loss of memory.
sl@0
     6
 *
sl@0
     7
 * Copyright (c) 1991-1994 The Regents of the University of California.
sl@0
     8
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
sl@0
     9
 * Copyright (c) 1998-1999 by Scriptics Corporation.
sl@0
    10
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    11
 *
sl@0
    12
 * See the file "license.terms" for information on usage and redistribution
sl@0
    13
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    14
 *
sl@0
    15
 * This code contributed by Karl Lehenbauer and Mark Diekhans
sl@0
    16
 *
sl@0
    17
 * RCS: @(#) $Id: tclCkalloc.c,v 1.19 2003/01/19 07:21:18 hobbs Exp $
sl@0
    18
 */
sl@0
    19
sl@0
    20
#include "tclInt.h"
sl@0
    21
#include "tclPort.h"
sl@0
    22
sl@0
    23
#define FALSE	0
sl@0
    24
#define TRUE	1
sl@0
    25
sl@0
    26
#ifdef TCL_MEM_DEBUG
sl@0
    27
sl@0
    28
/*
sl@0
    29
 * One of the following structures is allocated each time the
sl@0
    30
 * "memory tag" command is invoked, to hold the current tag.
sl@0
    31
 */
sl@0
    32
sl@0
    33
typedef struct MemTag {
sl@0
    34
    int refCount;		/* Number of mem_headers referencing
sl@0
    35
				 * this tag. */
sl@0
    36
    char string[4];		/* Actual size of string will be as
sl@0
    37
				 * large as needed for actual tag.  This
sl@0
    38
				 * must be the last field in the structure. */
sl@0
    39
} MemTag;
sl@0
    40
sl@0
    41
#define TAG_SIZE(bytesInString) ((unsigned) sizeof(MemTag) + bytesInString - 3)
sl@0
    42
sl@0
    43
static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers
sl@0
    44
				 * (set by "memory tag" command). */
sl@0
    45
sl@0
    46
/*
sl@0
    47
 * One of the following structures is allocated just before each
sl@0
    48
 * dynamically allocated chunk of memory, both to record information
sl@0
    49
 * about the chunk and to help detect chunk under-runs.
sl@0
    50
 */
sl@0
    51
sl@0
    52
#define LOW_GUARD_SIZE (8 + (32 - (sizeof(long) + sizeof(int)))%8)
sl@0
    53
struct mem_header {
sl@0
    54
    struct mem_header *flink;
sl@0
    55
    struct mem_header *blink;
sl@0
    56
    MemTag *tagPtr;		/* Tag from "memory tag" command;  may be
sl@0
    57
				 * NULL. */
sl@0
    58
    CONST char *file;
sl@0
    59
    long length;
sl@0
    60
    int line;
sl@0
    61
    unsigned char low_guard[LOW_GUARD_SIZE];
sl@0
    62
				/* Aligns body on 8-byte boundary, plus
sl@0
    63
				 * provides at least 8 additional guard bytes
sl@0
    64
				 * to detect underruns. */
sl@0
    65
    char body[1];		/* First byte of client's space.  Actual
sl@0
    66
				 * size of this field will be larger than
sl@0
    67
				 * one. */
sl@0
    68
};
sl@0
    69
sl@0
    70
#if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
sl@0
    71
static struct mem_header *allocHead = NULL;  /* List of allocated structures */
sl@0
    72
#else
sl@0
    73
typedef struct mem_header (*memHeaderPtr);
sl@0
    74
#define allocHead (*(memHeaderPtr*)get_allocHead())
sl@0
    75
#endif
sl@0
    76
sl@0
    77
#define GUARD_VALUE  0141
sl@0
    78
sl@0
    79
/*
sl@0
    80
 * The following macro determines the amount of guard space *above* each
sl@0
    81
 * chunk of memory.
sl@0
    82
 */
sl@0
    83
sl@0
    84
#define HIGH_GUARD_SIZE 8
sl@0
    85
sl@0
    86
/*
sl@0
    87
 * The following macro computes the offset of the "body" field within
sl@0
    88
 * mem_header.  It is used to get back to the header pointer from the
sl@0
    89
 * body pointer that's used by clients.
sl@0
    90
 */
sl@0
    91
sl@0
    92
#define BODY_OFFSET \
sl@0
    93
	((unsigned long) (&((struct mem_header *) 0)->body))
sl@0
    94
sl@0
    95
static int total_mallocs = 0;
sl@0
    96
static int total_frees = 0;
sl@0
    97
static int current_bytes_malloced = 0;
sl@0
    98
static int maximum_bytes_malloced = 0;
sl@0
    99
static int current_malloc_packets = 0;
sl@0
   100
static int maximum_malloc_packets = 0;
sl@0
   101
static int break_on_malloc = 0;
sl@0
   102
static int trace_on_at_malloc = 0;
sl@0
   103
static int  alloc_tracing = FALSE;
sl@0
   104
static int  init_malloced_bodies = TRUE;
sl@0
   105
#ifdef MEM_VALIDATE
sl@0
   106
    static int  validate_memory = TRUE;
sl@0
   107
#else
sl@0
   108
    static int  validate_memory = FALSE;
sl@0
   109
#endif
sl@0
   110
sl@0
   111
/*
sl@0
   112
 * The following variable indicates to TclFinalizeMemorySubsystem() 
sl@0
   113
 * that it should dump out the state of memory before exiting.  If the
sl@0
   114
 * value is non-NULL, it gives the name of the file in which to
sl@0
   115
 * dump memory usage information.
sl@0
   116
 */
sl@0
   117
sl@0
   118
char *tclMemDumpFileName = NULL;
sl@0
   119
sl@0
   120
static char *onExitMemDumpFileName = NULL;
sl@0
   121
static char dumpFile[100];	/* Records where to dump memory allocation
sl@0
   122
				 * information. */
sl@0
   123
sl@0
   124
/*
sl@0
   125
 * Mutex to serialize allocations.  This is a low-level mutex that must
sl@0
   126
 * be explicitly initialized.  This is necessary because the self
sl@0
   127
 * initializing mutexes use ckalloc...
sl@0
   128
 */
sl@0
   129
static Tcl_Mutex *ckallocMutexPtr;
sl@0
   130
static int ckallocInit = 0;
sl@0
   131
sl@0
   132
/*
sl@0
   133
 * Prototypes for procedures defined in this file:
sl@0
   134
 */
sl@0
   135
sl@0
   136
static int		CheckmemCmd _ANSI_ARGS_((ClientData clientData,
sl@0
   137
			    Tcl_Interp *interp, int argc, CONST char *argv[]));
sl@0
   138
static int		MemoryCmd _ANSI_ARGS_((ClientData clientData,
sl@0
   139
			    Tcl_Interp *interp, int argc, CONST char **argv));
sl@0
   140
static void		ValidateMemory _ANSI_ARGS_((
sl@0
   141
			    struct mem_header *memHeaderP, CONST char *file,
sl@0
   142
			    int line, int nukeGuards));
sl@0
   143

sl@0
   144
/*
sl@0
   145
 *----------------------------------------------------------------------
sl@0
   146
 *
sl@0
   147
 * TclInitDbCkalloc --
sl@0
   148
 *	Initialize the locks used by the allocator.
sl@0
   149
 *	This is only appropriate to call in a single threaded environment,
sl@0
   150
 *	such as during TclInitSubsystems.
sl@0
   151
 *
sl@0
   152
 *----------------------------------------------------------------------
sl@0
   153
 */
sl@0
   154
void
sl@0
   155
TclInitDbCkalloc() 
sl@0
   156
{
sl@0
   157
    if (!ckallocInit) {
sl@0
   158
	ckallocInit = 1;
sl@0
   159
	ckallocMutexPtr = Tcl_GetAllocMutex();
sl@0
   160
    }
sl@0
   161
}
sl@0
   162

sl@0
   163
/*
sl@0
   164
 *----------------------------------------------------------------------
sl@0
   165
 *
sl@0
   166
 * TclDumpMemoryInfo --
sl@0
   167
 *     Display the global memory management statistics.
sl@0
   168
 *
sl@0
   169
 *----------------------------------------------------------------------
sl@0
   170
 */
sl@0
   171
void
sl@0
   172
TclDumpMemoryInfo(outFile) 
sl@0
   173
    FILE *outFile;
sl@0
   174
{
sl@0
   175
    fprintf(outFile,"total mallocs             %10d\n", 
sl@0
   176
	    total_mallocs);
sl@0
   177
    fprintf(outFile,"total frees               %10d\n", 
sl@0
   178
	    total_frees);
sl@0
   179
    fprintf(outFile,"current packets allocated %10d\n", 
sl@0
   180
	    current_malloc_packets);
sl@0
   181
    fprintf(outFile,"current bytes allocated   %10d\n", 
sl@0
   182
	    current_bytes_malloced);
sl@0
   183
    fprintf(outFile,"maximum packets allocated %10d\n", 
sl@0
   184
	    maximum_malloc_packets);
sl@0
   185
    fprintf(outFile,"maximum bytes allocated   %10d\n", 
sl@0
   186
	    maximum_bytes_malloced);
sl@0
   187
}
sl@0
   188

sl@0
   189

sl@0
   190
/*
sl@0
   191
 *----------------------------------------------------------------------
sl@0
   192
 *
sl@0
   193
 * ValidateMemory --
sl@0
   194
 *
sl@0
   195
 *	Validate memory guard zones for a particular chunk of allocated
sl@0
   196
 *	memory.
sl@0
   197
 *
sl@0
   198
 * Results:
sl@0
   199
 *	None.
sl@0
   200
 *
sl@0
   201
 * Side effects:
sl@0
   202
 *	Prints validation information about the allocated memory to stderr.
sl@0
   203
 *
sl@0
   204
 *----------------------------------------------------------------------
sl@0
   205
 */
sl@0
   206
sl@0
   207
static void
sl@0
   208
ValidateMemory(memHeaderP, file, line, nukeGuards)
sl@0
   209
    struct mem_header *memHeaderP;	/* Memory chunk to validate */
sl@0
   210
    CONST char        *file;		/* File containing the call to
sl@0
   211
					 * Tcl_ValidateAllMemory */
sl@0
   212
    int                line;		/* Line number of call to
sl@0
   213
					 * Tcl_ValidateAllMemory */
sl@0
   214
    int                nukeGuards;	/* If non-zero, indicates that the
sl@0
   215
					 * memory guards are to be reset to 0
sl@0
   216
					 * after they have been printed */
sl@0
   217
{
sl@0
   218
    unsigned char *hiPtr;
sl@0
   219
    int   idx;
sl@0
   220
    int   guard_failed = FALSE;
sl@0
   221
    int byte;
sl@0
   222
    
sl@0
   223
    for (idx = 0; idx < LOW_GUARD_SIZE; idx++) {
sl@0
   224
        byte = *(memHeaderP->low_guard + idx);
sl@0
   225
        if (byte != GUARD_VALUE) {
sl@0
   226
            guard_failed = TRUE;
sl@0
   227
            fflush(stdout);
sl@0
   228
	    byte &= 0xff;
sl@0
   229
            fprintf(stderr, "low guard byte %d is 0x%x  \t%c\n", idx, byte,
sl@0
   230
		    (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */
sl@0
   231
        }
sl@0
   232
    }
sl@0
   233
    if (guard_failed) {
sl@0
   234
        TclDumpMemoryInfo (stderr);
sl@0
   235
        fprintf(stderr, "low guard failed at %lx, %s %d\n",
sl@0
   236
                 (long unsigned int) memHeaderP->body, file, line);
sl@0
   237
        fflush(stderr);  /* In case name pointer is bad. */
sl@0
   238
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length,
sl@0
   239
		memHeaderP->file, memHeaderP->line);
sl@0
   240
        panic ("Memory validation failure");
sl@0
   241
    }
sl@0
   242
sl@0
   243
    hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
sl@0
   244
    for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) {
sl@0
   245
        byte = *(hiPtr + idx);
sl@0
   246
        if (byte != GUARD_VALUE) {
sl@0
   247
            guard_failed = TRUE;
sl@0
   248
            fflush (stdout);
sl@0
   249
	    byte &= 0xff;
sl@0
   250
            fprintf(stderr, "hi guard byte %d is 0x%x  \t%c\n", idx, byte,
sl@0
   251
		    (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */
sl@0
   252
        }
sl@0
   253
    }
sl@0
   254
sl@0
   255
    if (guard_failed) {
sl@0
   256
        TclDumpMemoryInfo (stderr);
sl@0
   257
        fprintf(stderr, "high guard failed at %lx, %s %d\n",
sl@0
   258
                 (long unsigned int) memHeaderP->body, file, line);
sl@0
   259
        fflush(stderr);  /* In case name pointer is bad. */
sl@0
   260
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n",
sl@0
   261
		memHeaderP->length, memHeaderP->file,
sl@0
   262
		memHeaderP->line);
sl@0
   263
        panic("Memory validation failure");
sl@0
   264
    }
sl@0
   265
sl@0
   266
    if (nukeGuards) {
sl@0
   267
        memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE); 
sl@0
   268
        memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE); 
sl@0
   269
    }
sl@0
   270
sl@0
   271
}
sl@0
   272

sl@0
   273
/*
sl@0
   274
 *----------------------------------------------------------------------
sl@0
   275
 *
sl@0
   276
 * Tcl_ValidateAllMemory --
sl@0
   277
 *
sl@0
   278
 *	Validate memory guard regions for all allocated memory.
sl@0
   279
 *
sl@0
   280
 * Results:
sl@0
   281
 *	None.
sl@0
   282
 *
sl@0
   283
 * Side effects:
sl@0
   284
 *	Displays memory validation information to stderr.
sl@0
   285
 *
sl@0
   286
 *----------------------------------------------------------------------
sl@0
   287
 */
sl@0
   288
EXPORT_C void
sl@0
   289
Tcl_ValidateAllMemory (file, line)
sl@0
   290
    CONST char  *file;	/* File from which Tcl_ValidateAllMemory was called */
sl@0
   291
    int          line;	/* Line number of call to Tcl_ValidateAllMemory */
sl@0
   292
{
sl@0
   293
    struct mem_header *memScanP;
sl@0
   294
sl@0
   295
    if (!ckallocInit) {
sl@0
   296
	TclInitDbCkalloc();
sl@0
   297
    }
sl@0
   298
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
   299
    for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
sl@0
   300
        ValidateMemory(memScanP, file, line, FALSE);
sl@0
   301
    }
sl@0
   302
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
   303
}
sl@0
   304

sl@0
   305
/*
sl@0
   306
 *----------------------------------------------------------------------
sl@0
   307
 *
sl@0
   308
 * Tcl_DumpActiveMemory --
sl@0
   309
 *
sl@0
   310
 *	Displays all allocated memory to a file; if no filename is given,
sl@0
   311
 *	information will be written to stderr.
sl@0
   312
 *
sl@0
   313
 * Results:
sl@0
   314
 *	Return TCL_ERROR if an error accessing the file occurs, `errno' 
sl@0
   315
 *	will have the file error number left in it.
sl@0
   316
 *----------------------------------------------------------------------
sl@0
   317
 */
sl@0
   318
EXPORT_C int
sl@0
   319
Tcl_DumpActiveMemory (fileName)
sl@0
   320
    CONST char *fileName;		/* Name of the file to write info to */
sl@0
   321
{
sl@0
   322
    FILE              *fileP;
sl@0
   323
    struct mem_header *memScanP;
sl@0
   324
    char              *address;
sl@0
   325
sl@0
   326
    if (fileName == NULL) {
sl@0
   327
	fileP = stderr;
sl@0
   328
    } else {
sl@0
   329
	fileP = fopen(fileName, "w");
sl@0
   330
	if (fileP == NULL) {
sl@0
   331
	    return TCL_ERROR;
sl@0
   332
	}
sl@0
   333
    }
sl@0
   334
sl@0
   335
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
   336
    for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
sl@0
   337
        address = &memScanP->body [0];
sl@0
   338
        fprintf(fileP, "%8lx - %8lx  %7ld @ %s %d %s",
sl@0
   339
		(long unsigned int) address,
sl@0
   340
                 (long unsigned int) address + memScanP->length - 1,
sl@0
   341
		 memScanP->length, memScanP->file, memScanP->line,
sl@0
   342
		 (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string);
sl@0
   343
	(void) fputc('\n', fileP);
sl@0
   344
    }
sl@0
   345
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
   346
sl@0
   347
    if (fileP != stderr) {
sl@0
   348
	fclose (fileP);
sl@0
   349
    }
sl@0
   350
    return TCL_OK;
sl@0
   351
}
sl@0
   352

sl@0
   353
/*
sl@0
   354
 *----------------------------------------------------------------------
sl@0
   355
 *
sl@0
   356
 * Tcl_DbCkalloc - debugging ckalloc
sl@0
   357
 *
sl@0
   358
 *        Allocate the requested amount of space plus some extra for
sl@0
   359
 *        guard bands at both ends of the request, plus a size, panicing 
sl@0
   360
 *        if there isn't enough space, then write in the guard bands
sl@0
   361
 *        and return the address of the space in the middle that the
sl@0
   362
 *        user asked for.
sl@0
   363
 *
sl@0
   364
 *        The second and third arguments are file and line, these contain
sl@0
   365
 *        the filename and line number corresponding to the caller.
sl@0
   366
 *        These are sent by the ckalloc macro; it uses the preprocessor
sl@0
   367
 *        autodefines __FILE__ and __LINE__.
sl@0
   368
 *
sl@0
   369
 *----------------------------------------------------------------------
sl@0
   370
 */
sl@0
   371
EXPORT_C char *
sl@0
   372
Tcl_DbCkalloc(size, file, line)
sl@0
   373
    unsigned int size;
sl@0
   374
    CONST char  *file;
sl@0
   375
    int          line;
sl@0
   376
{
sl@0
   377
    struct mem_header *result;
sl@0
   378
sl@0
   379
    if (validate_memory)
sl@0
   380
        Tcl_ValidateAllMemory (file, line);
sl@0
   381
sl@0
   382
    result = (struct mem_header *) TclpAlloc((unsigned)size + 
sl@0
   383
                              sizeof(struct mem_header) + HIGH_GUARD_SIZE);
sl@0
   384
    if (result == NULL) {
sl@0
   385
        fflush(stdout);
sl@0
   386
        TclDumpMemoryInfo(stderr);
sl@0
   387
        panic("unable to alloc %u bytes, %s line %d", size, file, line);
sl@0
   388
    }
sl@0
   389
sl@0
   390
    /*
sl@0
   391
     * Fill in guard zones and size.  Also initialize the contents of
sl@0
   392
     * the block with bogus bytes to detect uses of initialized data.
sl@0
   393
     * Link into allocated list.
sl@0
   394
     */
sl@0
   395
    if (init_malloced_bodies) {
sl@0
   396
        memset ((VOID *) result, GUARD_VALUE,
sl@0
   397
		size + sizeof(struct mem_header) + HIGH_GUARD_SIZE);
sl@0
   398
    } else {
sl@0
   399
	memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE);
sl@0
   400
	memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE);
sl@0
   401
    }
sl@0
   402
    if (!ckallocInit) {
sl@0
   403
	TclInitDbCkalloc();
sl@0
   404
    }
sl@0
   405
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
   406
    result->length = size;
sl@0
   407
    result->tagPtr = curTagPtr;
sl@0
   408
    if (curTagPtr != NULL) {
sl@0
   409
	curTagPtr->refCount++;
sl@0
   410
    }
sl@0
   411
    result->file = file;
sl@0
   412
    result->line = line;
sl@0
   413
    result->flink = allocHead;
sl@0
   414
    result->blink = NULL;
sl@0
   415
sl@0
   416
    if (allocHead != NULL)
sl@0
   417
        allocHead->blink = result;
sl@0
   418
    allocHead = result;
sl@0
   419
sl@0
   420
    total_mallocs++;
sl@0
   421
    if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
sl@0
   422
        (void) fflush(stdout);
sl@0
   423
        fprintf(stderr, "reached malloc trace enable point (%d)\n",
sl@0
   424
                total_mallocs);
sl@0
   425
        fflush(stderr);
sl@0
   426
        alloc_tracing = TRUE;
sl@0
   427
        trace_on_at_malloc = 0;
sl@0
   428
    }
sl@0
   429
sl@0
   430
    if (alloc_tracing)
sl@0
   431
        fprintf(stderr,"ckalloc %lx %u %s %d\n",
sl@0
   432
		(long unsigned int) result->body, size, file, line);
sl@0
   433
sl@0
   434
    if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
sl@0
   435
        break_on_malloc = 0;
sl@0
   436
        (void) fflush(stdout);
sl@0
   437
        fprintf(stderr,"reached malloc break limit (%d)\n", 
sl@0
   438
                total_mallocs);
sl@0
   439
        fprintf(stderr, "program will now enter C debugger\n");
sl@0
   440
        (void) fflush(stderr);
sl@0
   441
	abort();
sl@0
   442
    }
sl@0
   443
sl@0
   444
    current_malloc_packets++;
sl@0
   445
    if (current_malloc_packets > maximum_malloc_packets)
sl@0
   446
        maximum_malloc_packets = current_malloc_packets;
sl@0
   447
    current_bytes_malloced += size;
sl@0
   448
    if (current_bytes_malloced > maximum_bytes_malloced)
sl@0
   449
        maximum_bytes_malloced = current_bytes_malloced;
sl@0
   450
sl@0
   451
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
   452
sl@0
   453
    return result->body;
sl@0
   454
}
sl@0
   455
sl@0
   456
char *
sl@0
   457
Tcl_AttemptDbCkalloc(size, file, line)
sl@0
   458
    unsigned int size;
sl@0
   459
    CONST char  *file;
sl@0
   460
    int          line;
sl@0
   461
{
sl@0
   462
    struct mem_header *result;
sl@0
   463
sl@0
   464
    if (validate_memory)
sl@0
   465
        Tcl_ValidateAllMemory (file, line);
sl@0
   466
sl@0
   467
    result = (struct mem_header *) TclpAlloc((unsigned)size + 
sl@0
   468
                              sizeof(struct mem_header) + HIGH_GUARD_SIZE);
sl@0
   469
    if (result == NULL) {
sl@0
   470
        fflush(stdout);
sl@0
   471
        TclDumpMemoryInfo(stderr);
sl@0
   472
	return NULL;
sl@0
   473
    }
sl@0
   474
sl@0
   475
    /*
sl@0
   476
     * Fill in guard zones and size.  Also initialize the contents of
sl@0
   477
     * the block with bogus bytes to detect uses of initialized data.
sl@0
   478
     * Link into allocated list.
sl@0
   479
     */
sl@0
   480
    if (init_malloced_bodies) {
sl@0
   481
        memset ((VOID *) result, GUARD_VALUE,
sl@0
   482
		size + sizeof(struct mem_header) + HIGH_GUARD_SIZE);
sl@0
   483
    } else {
sl@0
   484
	memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE);
sl@0
   485
	memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE);
sl@0
   486
    }
sl@0
   487
    if (!ckallocInit) {
sl@0
   488
	TclInitDbCkalloc();
sl@0
   489
    }
sl@0
   490
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
   491
    result->length = size;
sl@0
   492
    result->tagPtr = curTagPtr;
sl@0
   493
    if (curTagPtr != NULL) {
sl@0
   494
	curTagPtr->refCount++;
sl@0
   495
    }
sl@0
   496
    result->file = file;
sl@0
   497
    result->line = line;
sl@0
   498
    result->flink = allocHead;
sl@0
   499
    result->blink = NULL;
sl@0
   500
sl@0
   501
    if (allocHead != NULL)
sl@0
   502
        allocHead->blink = result;
sl@0
   503
    allocHead = result;
sl@0
   504
sl@0
   505
    total_mallocs++;
sl@0
   506
    if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
sl@0
   507
        (void) fflush(stdout);
sl@0
   508
        fprintf(stderr, "reached malloc trace enable point (%d)\n",
sl@0
   509
                total_mallocs);
sl@0
   510
        fflush(stderr);
sl@0
   511
        alloc_tracing = TRUE;
sl@0
   512
        trace_on_at_malloc = 0;
sl@0
   513
    }
sl@0
   514
sl@0
   515
    if (alloc_tracing)
sl@0
   516
        fprintf(stderr,"ckalloc %lx %u %s %d\n",
sl@0
   517
		(long unsigned int) result->body, size, file, line);
sl@0
   518
sl@0
   519
    if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
sl@0
   520
        break_on_malloc = 0;
sl@0
   521
        (void) fflush(stdout);
sl@0
   522
        fprintf(stderr,"reached malloc break limit (%d)\n", 
sl@0
   523
                total_mallocs);
sl@0
   524
        fprintf(stderr, "program will now enter C debugger\n");
sl@0
   525
        (void) fflush(stderr);
sl@0
   526
	abort();
sl@0
   527
    }
sl@0
   528
sl@0
   529
    current_malloc_packets++;
sl@0
   530
    if (current_malloc_packets > maximum_malloc_packets)
sl@0
   531
        maximum_malloc_packets = current_malloc_packets;
sl@0
   532
    current_bytes_malloced += size;
sl@0
   533
    if (current_bytes_malloced > maximum_bytes_malloced)
sl@0
   534
        maximum_bytes_malloced = current_bytes_malloced;
sl@0
   535
sl@0
   536
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
   537
sl@0
   538
    return result->body;
sl@0
   539
}
sl@0
   540
sl@0
   541

sl@0
   542
/*
sl@0
   543
 *----------------------------------------------------------------------
sl@0
   544
 *
sl@0
   545
 * Tcl_DbCkfree - debugging ckfree
sl@0
   546
 *
sl@0
   547
 *        Verify that the low and high guards are intact, and if so
sl@0
   548
 *        then free the buffer else panic.
sl@0
   549
 *
sl@0
   550
 *        The guards are erased after being checked to catch duplicate
sl@0
   551
 *        frees.
sl@0
   552
 *
sl@0
   553
 *        The second and third arguments are file and line, these contain
sl@0
   554
 *        the filename and line number corresponding to the caller.
sl@0
   555
 *        These are sent by the ckfree macro; it uses the preprocessor
sl@0
   556
 *        autodefines __FILE__ and __LINE__.
sl@0
   557
 *
sl@0
   558
 *----------------------------------------------------------------------
sl@0
   559
 */
sl@0
   560
sl@0
   561
EXPORT_C int
sl@0
   562
Tcl_DbCkfree(ptr, file, line)
sl@0
   563
    char       *ptr;
sl@0
   564
    CONST char *file;
sl@0
   565
    int         line;
sl@0
   566
{
sl@0
   567
    struct mem_header *memp;
sl@0
   568
sl@0
   569
    if (ptr == NULL) {
sl@0
   570
	return 0;
sl@0
   571
    }
sl@0
   572
sl@0
   573
    /*
sl@0
   574
     * The following cast is *very* tricky.  Must convert the pointer
sl@0
   575
     * to an integer before doing arithmetic on it, because otherwise
sl@0
   576
     * the arithmetic will be done differently (and incorrectly) on
sl@0
   577
     * word-addressed machines such as Crays (will subtract only bytes,
sl@0
   578
     * even though BODY_OFFSET is in words on these machines).
sl@0
   579
     */
sl@0
   580
sl@0
   581
    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
sl@0
   582
sl@0
   583
    if (alloc_tracing) {
sl@0
   584
        fprintf(stderr, "ckfree %lx %ld %s %d\n",
sl@0
   585
		(long unsigned int) memp->body, memp->length, file, line);
sl@0
   586
    }
sl@0
   587
sl@0
   588
    if (validate_memory) {
sl@0
   589
        Tcl_ValidateAllMemory(file, line);
sl@0
   590
    }
sl@0
   591
sl@0
   592
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
   593
    ValidateMemory(memp, file, line, TRUE);
sl@0
   594
    if (init_malloced_bodies) {
sl@0
   595
	memset((VOID *) ptr, GUARD_VALUE, (size_t) memp->length);
sl@0
   596
    }
sl@0
   597
sl@0
   598
    total_frees++;
sl@0
   599
    current_malloc_packets--;
sl@0
   600
    current_bytes_malloced -= memp->length;
sl@0
   601
sl@0
   602
    if (memp->tagPtr != NULL) {
sl@0
   603
	memp->tagPtr->refCount--;
sl@0
   604
	if ((memp->tagPtr->refCount == 0) && (curTagPtr != memp->tagPtr)) {
sl@0
   605
	    TclpFree((char *) memp->tagPtr);
sl@0
   606
	}
sl@0
   607
    }
sl@0
   608
sl@0
   609
    /*
sl@0
   610
     * Delink from allocated list
sl@0
   611
     */
sl@0
   612
    if (memp->flink != NULL)
sl@0
   613
        memp->flink->blink = memp->blink;
sl@0
   614
    if (memp->blink != NULL)
sl@0
   615
        memp->blink->flink = memp->flink;
sl@0
   616
    if (allocHead == memp)
sl@0
   617
        allocHead = memp->flink;
sl@0
   618
    TclpFree((char *) memp);
sl@0
   619
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
   620
sl@0
   621
    return 0;
sl@0
   622
}
sl@0
   623

sl@0
   624
/*
sl@0
   625
 *--------------------------------------------------------------------
sl@0
   626
 *
sl@0
   627
 * Tcl_DbCkrealloc - debugging ckrealloc
sl@0
   628
 *
sl@0
   629
 *	Reallocate a chunk of memory by allocating a new one of the
sl@0
   630
 *	right size, copying the old data to the new location, and then
sl@0
   631
 *	freeing the old memory space, using all the memory checking
sl@0
   632
 *	features of this package.
sl@0
   633
 *
sl@0
   634
 *--------------------------------------------------------------------
sl@0
   635
 */
sl@0
   636
EXPORT_C char *
sl@0
   637
Tcl_DbCkrealloc(ptr, size, file, line)
sl@0
   638
    char        *ptr;
sl@0
   639
    unsigned int size;
sl@0
   640
    CONST char  *file;
sl@0
   641
    int          line;
sl@0
   642
{
sl@0
   643
    char *new;
sl@0
   644
    unsigned int copySize;
sl@0
   645
    struct mem_header *memp;
sl@0
   646
sl@0
   647
    if (ptr == NULL) {
sl@0
   648
	return Tcl_DbCkalloc(size, file, line);
sl@0
   649
    }
sl@0
   650
sl@0
   651
    /*
sl@0
   652
     * See comment from Tcl_DbCkfree before you change the following
sl@0
   653
     * line.
sl@0
   654
     */
sl@0
   655
sl@0
   656
    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
sl@0
   657
sl@0
   658
    copySize = size;
sl@0
   659
    if (copySize > (unsigned int) memp->length) {
sl@0
   660
	copySize = memp->length;
sl@0
   661
    }
sl@0
   662
    new = Tcl_DbCkalloc(size, file, line);
sl@0
   663
    memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize);
sl@0
   664
    Tcl_DbCkfree(ptr, file, line);
sl@0
   665
    return new;
sl@0
   666
}
sl@0
   667
sl@0
   668
char *
sl@0
   669
Tcl_AttemptDbCkrealloc(ptr, size, file, line)
sl@0
   670
    char        *ptr;
sl@0
   671
    unsigned int size;
sl@0
   672
    CONST char  *file;
sl@0
   673
    int          line;
sl@0
   674
{
sl@0
   675
    char *new;
sl@0
   676
    unsigned int copySize;
sl@0
   677
    struct mem_header *memp;
sl@0
   678
sl@0
   679
    if (ptr == NULL) {
sl@0
   680
	return Tcl_AttemptDbCkalloc(size, file, line);
sl@0
   681
    }
sl@0
   682
sl@0
   683
    /*
sl@0
   684
     * See comment from Tcl_DbCkfree before you change the following
sl@0
   685
     * line.
sl@0
   686
     */
sl@0
   687
sl@0
   688
    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET);
sl@0
   689
sl@0
   690
    copySize = size;
sl@0
   691
    if (copySize > (unsigned int) memp->length) {
sl@0
   692
	copySize = memp->length;
sl@0
   693
    }
sl@0
   694
    new = Tcl_AttemptDbCkalloc(size, file, line);
sl@0
   695
    if (new == NULL) {
sl@0
   696
	return NULL;
sl@0
   697
    }
sl@0
   698
    memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize);
sl@0
   699
    Tcl_DbCkfree(ptr, file, line);
sl@0
   700
    return new;
sl@0
   701
}
sl@0
   702
sl@0
   703

sl@0
   704
/*
sl@0
   705
 *----------------------------------------------------------------------
sl@0
   706
 *
sl@0
   707
 * Tcl_Alloc, et al. --
sl@0
   708
 *
sl@0
   709
 *	These functions are defined in terms of the debugging versions
sl@0
   710
 *	when TCL_MEM_DEBUG is set.
sl@0
   711
 *
sl@0
   712
 * Results:
sl@0
   713
 *	Same as the debug versions.
sl@0
   714
 *
sl@0
   715
 * Side effects:
sl@0
   716
 *	Same as the debug versions.
sl@0
   717
 *
sl@0
   718
 *----------------------------------------------------------------------
sl@0
   719
 */
sl@0
   720
sl@0
   721
#undef Tcl_Alloc
sl@0
   722
#undef Tcl_Free
sl@0
   723
#undef Tcl_Realloc
sl@0
   724
#undef Tcl_AttemptAlloc
sl@0
   725
#undef Tcl_AttemptRealloc
sl@0
   726
sl@0
   727
EXPORT_C char *
sl@0
   728
Tcl_Alloc(size)
sl@0
   729
    unsigned int size;
sl@0
   730
{
sl@0
   731
    return Tcl_DbCkalloc(size, "unknown", 0);
sl@0
   732
}
sl@0
   733
sl@0
   734
char *
sl@0
   735
Tcl_AttemptAlloc(size)
sl@0
   736
    unsigned int size;
sl@0
   737
{
sl@0
   738
    return Tcl_AttemptDbCkalloc(size, "unknown", 0);
sl@0
   739
}
sl@0
   740
sl@0
   741
EXPORT_C void
sl@0
   742
Tcl_Free(ptr)
sl@0
   743
    char *ptr;
sl@0
   744
{
sl@0
   745
    Tcl_DbCkfree(ptr, "unknown", 0);
sl@0
   746
}
sl@0
   747
sl@0
   748
EXPORT_C char *
sl@0
   749
Tcl_Realloc(ptr, size)
sl@0
   750
    char *ptr;
sl@0
   751
    unsigned int size;
sl@0
   752
{
sl@0
   753
    return Tcl_DbCkrealloc(ptr, size, "unknown", 0);
sl@0
   754
}
sl@0
   755
char *
sl@0
   756
Tcl_AttemptRealloc(ptr, size)
sl@0
   757
    char *ptr;
sl@0
   758
    unsigned int size;
sl@0
   759
{
sl@0
   760
    return Tcl_AttemptDbCkrealloc(ptr, size, "unknown", 0);
sl@0
   761
}
sl@0
   762

sl@0
   763
/*
sl@0
   764
 *----------------------------------------------------------------------
sl@0
   765
 *
sl@0
   766
 * MemoryCmd --
sl@0
   767
 *	Implements the Tcl "memory" command, which provides Tcl-level
sl@0
   768
 *	control of Tcl memory debugging information.
sl@0
   769
 *		memory active $file
sl@0
   770
 *		memory break_on_malloc $count
sl@0
   771
 *		memory info
sl@0
   772
 *		memory init on|off
sl@0
   773
 *		memory onexit $file
sl@0
   774
 *		memory tag $string
sl@0
   775
 *		memory trace on|off
sl@0
   776
 *		memory trace_on_at_malloc $count
sl@0
   777
 *		memory validate on|off
sl@0
   778
 *
sl@0
   779
 * Results:
sl@0
   780
 *     Standard TCL results.
sl@0
   781
 *
sl@0
   782
 *----------------------------------------------------------------------
sl@0
   783
 */
sl@0
   784
	/* ARGSUSED */
sl@0
   785
static int
sl@0
   786
MemoryCmd (clientData, interp, argc, argv)
sl@0
   787
    ClientData  clientData;
sl@0
   788
    Tcl_Interp *interp;
sl@0
   789
    int         argc;
sl@0
   790
    CONST char  **argv;
sl@0
   791
{
sl@0
   792
    CONST char *fileName;
sl@0
   793
    Tcl_DString buffer;
sl@0
   794
    int result;
sl@0
   795
sl@0
   796
    if (argc < 2) {
sl@0
   797
	Tcl_AppendResult(interp, "wrong # args: should be \"",
sl@0
   798
		argv[0], " option [args..]\"", (char *) NULL);
sl@0
   799
	return TCL_ERROR;
sl@0
   800
    }
sl@0
   801
sl@0
   802
    if ((strcmp(argv[1],"active") == 0) || (strcmp(argv[1],"display") == 0)) {
sl@0
   803
        if (argc != 3) {
sl@0
   804
	    Tcl_AppendResult(interp, "wrong # args: should be \"",
sl@0
   805
		    argv[0], " ", argv[1], " file\"", (char *) NULL);
sl@0
   806
	    return TCL_ERROR;
sl@0
   807
	}
sl@0
   808
	fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);
sl@0
   809
	if (fileName == NULL) {
sl@0
   810
	    return TCL_ERROR;
sl@0
   811
	}
sl@0
   812
	result = Tcl_DumpActiveMemory (fileName);
sl@0
   813
	Tcl_DStringFree(&buffer);
sl@0
   814
	if (result != TCL_OK) {
sl@0
   815
	    Tcl_AppendResult(interp, "error accessing ", argv[2], 
sl@0
   816
		    (char *) NULL);
sl@0
   817
	    return TCL_ERROR;
sl@0
   818
	}
sl@0
   819
	return TCL_OK;
sl@0
   820
    }
sl@0
   821
    if (strcmp(argv[1],"break_on_malloc") == 0) {
sl@0
   822
        if (argc != 3) {
sl@0
   823
            goto argError;
sl@0
   824
	}
sl@0
   825
        if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) {
sl@0
   826
	    return TCL_ERROR;
sl@0
   827
	}
sl@0
   828
        return TCL_OK;
sl@0
   829
    }
sl@0
   830
    if (strcmp(argv[1],"info") == 0) {
sl@0
   831
	char buf[400];
sl@0
   832
	sprintf(buf, "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n",
sl@0
   833
	    "total mallocs", total_mallocs, "total frees", total_frees,
sl@0
   834
	    "current packets allocated", current_malloc_packets,
sl@0
   835
	    "current bytes allocated", current_bytes_malloced,
sl@0
   836
	    "maximum packets allocated", maximum_malloc_packets,
sl@0
   837
	    "maximum bytes allocated", maximum_bytes_malloced);
sl@0
   838
	Tcl_SetResult(interp, buf, TCL_VOLATILE);
sl@0
   839
        return TCL_OK;
sl@0
   840
    }
sl@0
   841
    if (strcmp(argv[1],"init") == 0) {
sl@0
   842
        if (argc != 3) {
sl@0
   843
            goto bad_suboption;
sl@0
   844
	}
sl@0
   845
        init_malloced_bodies = (strcmp(argv[2],"on") == 0);
sl@0
   846
        return TCL_OK;
sl@0
   847
    }
sl@0
   848
    if (strcmp(argv[1],"onexit") == 0) {
sl@0
   849
        if (argc != 3) {
sl@0
   850
	    Tcl_AppendResult(interp, "wrong # args: should be \"",
sl@0
   851
		    argv[0], " onexit file\"", (char *) NULL);
sl@0
   852
	    return TCL_ERROR;
sl@0
   853
	}
sl@0
   854
	fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);
sl@0
   855
	if (fileName == NULL) {
sl@0
   856
	    return TCL_ERROR;
sl@0
   857
	}
sl@0
   858
	onExitMemDumpFileName = dumpFile;
sl@0
   859
	strcpy(onExitMemDumpFileName,fileName);
sl@0
   860
	Tcl_DStringFree(&buffer);
sl@0
   861
	return TCL_OK;
sl@0
   862
    }
sl@0
   863
    if (strcmp(argv[1],"tag") == 0) {
sl@0
   864
	if (argc != 3) {
sl@0
   865
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   866
		    " tag string\"", (char *) NULL);
sl@0
   867
	    return TCL_ERROR;
sl@0
   868
	}
sl@0
   869
	if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) {
sl@0
   870
	    TclpFree((char *) curTagPtr);
sl@0
   871
	}
sl@0
   872
	curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(strlen(argv[2])));
sl@0
   873
	curTagPtr->refCount = 0;
sl@0
   874
	strcpy(curTagPtr->string, argv[2]);
sl@0
   875
	return TCL_OK;
sl@0
   876
    }
sl@0
   877
    if (strcmp(argv[1],"trace") == 0) {
sl@0
   878
        if (argc != 3) {
sl@0
   879
            goto bad_suboption;
sl@0
   880
	}
sl@0
   881
        alloc_tracing = (strcmp(argv[2],"on") == 0);
sl@0
   882
        return TCL_OK;
sl@0
   883
    }
sl@0
   884
sl@0
   885
    if (strcmp(argv[1],"trace_on_at_malloc") == 0) {
sl@0
   886
        if (argc != 3) {
sl@0
   887
            goto argError;
sl@0
   888
	}
sl@0
   889
        if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) {
sl@0
   890
	    return TCL_ERROR;
sl@0
   891
	}
sl@0
   892
	return TCL_OK;
sl@0
   893
    }
sl@0
   894
    if (strcmp(argv[1],"validate") == 0) {
sl@0
   895
        if (argc != 3) {
sl@0
   896
	    goto bad_suboption;
sl@0
   897
	}
sl@0
   898
        validate_memory = (strcmp(argv[2],"on") == 0);
sl@0
   899
        return TCL_OK;
sl@0
   900
    }
sl@0
   901
sl@0
   902
    Tcl_AppendResult(interp, "bad option \"", argv[1],
sl@0
   903
	    "\": should be active, break_on_malloc, info, init, onexit, ",
sl@0
   904
	    "tag, trace, trace_on_at_malloc, or validate", (char *) NULL);
sl@0
   905
    return TCL_ERROR;
sl@0
   906
sl@0
   907
argError:
sl@0
   908
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   909
	    " ", argv[1], " count\"", (char *) NULL);
sl@0
   910
    return TCL_ERROR;
sl@0
   911
sl@0
   912
bad_suboption:
sl@0
   913
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   914
	    " ", argv[1], " on|off\"", (char *) NULL);
sl@0
   915
    return TCL_ERROR;
sl@0
   916
}
sl@0
   917

sl@0
   918
/*
sl@0
   919
 *----------------------------------------------------------------------
sl@0
   920
 *
sl@0
   921
 * CheckmemCmd --
sl@0
   922
 *
sl@0
   923
 *	This is the command procedure for the "checkmem" command, which
sl@0
   924
 *	causes the application to exit after printing information about
sl@0
   925
 *	memory usage to the file passed to this command as its first
sl@0
   926
 *	argument.
sl@0
   927
 *
sl@0
   928
 * Results:
sl@0
   929
 *	Returns a standard Tcl completion code.
sl@0
   930
 *
sl@0
   931
 * Side effects:
sl@0
   932
 *	None.
sl@0
   933
 *
sl@0
   934
 *----------------------------------------------------------------------
sl@0
   935
 */
sl@0
   936
sl@0
   937
static int
sl@0
   938
CheckmemCmd(clientData, interp, argc, argv)
sl@0
   939
    ClientData clientData;		/* Not used. */
sl@0
   940
    Tcl_Interp *interp;			/* Interpreter for evaluation. */
sl@0
   941
    int argc;				/* Number of arguments. */
sl@0
   942
    CONST char *argv[];			/* String values of arguments. */
sl@0
   943
{
sl@0
   944
    if (argc != 2) {
sl@0
   945
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   946
		" fileName\"", (char *) NULL);
sl@0
   947
	return TCL_ERROR;
sl@0
   948
    }
sl@0
   949
    tclMemDumpFileName = dumpFile;
sl@0
   950
    strcpy(tclMemDumpFileName, argv[1]);
sl@0
   951
    return TCL_OK;
sl@0
   952
}
sl@0
   953

sl@0
   954
/*
sl@0
   955
 *----------------------------------------------------------------------
sl@0
   956
 *
sl@0
   957
 * Tcl_InitMemory --
sl@0
   958
 *
sl@0
   959
 *	Create the "memory" and "checkmem" commands in the given
sl@0
   960
 *	interpreter.
sl@0
   961
 *
sl@0
   962
 * Results:
sl@0
   963
 *	None.
sl@0
   964
 *
sl@0
   965
 * Side effects:
sl@0
   966
 *	New commands are added to the interpreter.
sl@0
   967
 *
sl@0
   968
 *----------------------------------------------------------------------
sl@0
   969
 */
sl@0
   970
sl@0
   971
EXPORT_C void
sl@0
   972
Tcl_InitMemory(interp)
sl@0
   973
    Tcl_Interp *interp;	/* Interpreter in which commands should be added */
sl@0
   974
{
sl@0
   975
    TclInitDbCkalloc();
sl@0
   976
    Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData) NULL, 
sl@0
   977
	    (Tcl_CmdDeleteProc *) NULL);
sl@0
   978
    Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
sl@0
   979
	    (Tcl_CmdDeleteProc *) NULL);
sl@0
   980
}
sl@0
   981
sl@0
   982
sl@0
   983
#else	/* TCL_MEM_DEBUG */
sl@0
   984
sl@0
   985
/* This is the !TCL_MEM_DEBUG case */
sl@0
   986
sl@0
   987
#undef Tcl_InitMemory
sl@0
   988
#undef Tcl_DumpActiveMemory
sl@0
   989
#undef Tcl_ValidateAllMemory
sl@0
   990
sl@0
   991

sl@0
   992
/*
sl@0
   993
 *----------------------------------------------------------------------
sl@0
   994
 *
sl@0
   995
 * Tcl_Alloc --
sl@0
   996
 *     Interface to TclpAlloc when TCL_MEM_DEBUG is disabled.  It does check
sl@0
   997
 *     that memory was actually allocated.
sl@0
   998
 *
sl@0
   999
 *----------------------------------------------------------------------
sl@0
  1000
 */
sl@0
  1001
sl@0
  1002
EXPORT_C char *
sl@0
  1003
Tcl_Alloc (size)
sl@0
  1004
    unsigned int size;
sl@0
  1005
{
sl@0
  1006
    char *result;
sl@0
  1007
sl@0
  1008
    result = TclpAlloc(size);
sl@0
  1009
    /*
sl@0
  1010
     * Most systems will not alloc(0), instead bumping it to one so
sl@0
  1011
     * that NULL isn't returned.  Some systems (AIX, Tru64) will alloc(0)
sl@0
  1012
     * by returning NULL, so we have to check that the NULL we get is
sl@0
  1013
     * not in response to alloc(0).
sl@0
  1014
     *
sl@0
  1015
     * The ANSI spec actually says that systems either return NULL *or*
sl@0
  1016
     * a special pointer on failure, but we only check for NULL
sl@0
  1017
     */
sl@0
  1018
    if ((result == NULL) && size) {
sl@0
  1019
	panic("unable to alloc %u bytes", size);
sl@0
  1020
    }
sl@0
  1021
    return result;
sl@0
  1022
}
sl@0
  1023
sl@0
  1024
EXPORT_C char *
sl@0
  1025
Tcl_DbCkalloc(size, file, line)
sl@0
  1026
    unsigned int size;
sl@0
  1027
    CONST char  *file;
sl@0
  1028
    int          line;
sl@0
  1029
{
sl@0
  1030
    char *result;
sl@0
  1031
sl@0
  1032
    result = (char *) TclpAlloc(size);
sl@0
  1033
sl@0
  1034
    if ((result == NULL) && size) {
sl@0
  1035
        fflush(stdout);
sl@0
  1036
        panic("unable to alloc %u bytes, %s line %d", size, file, line);
sl@0
  1037
    }
sl@0
  1038
    return result;
sl@0
  1039
}
sl@0
  1040

sl@0
  1041
/*
sl@0
  1042
 *----------------------------------------------------------------------
sl@0
  1043
 *
sl@0
  1044
 * Tcl_AttemptAlloc --
sl@0
  1045
 *     Interface to TclpAlloc when TCL_MEM_DEBUG is disabled.  It does not
sl@0
  1046
 *     check that memory was actually allocated.
sl@0
  1047
 *
sl@0
  1048
 *----------------------------------------------------------------------
sl@0
  1049
 */
sl@0
  1050
sl@0
  1051
EXPORT_C char *
sl@0
  1052
Tcl_AttemptAlloc (size)
sl@0
  1053
    unsigned int size;
sl@0
  1054
{
sl@0
  1055
    char *result;
sl@0
  1056
sl@0
  1057
    result = TclpAlloc(size);
sl@0
  1058
    return result;
sl@0
  1059
}
sl@0
  1060
sl@0
  1061
EXPORT_C char *
sl@0
  1062
Tcl_AttemptDbCkalloc(size, file, line)
sl@0
  1063
    unsigned int size;
sl@0
  1064
    CONST char  *file;
sl@0
  1065
    int          line;
sl@0
  1066
{
sl@0
  1067
    char *result;
sl@0
  1068
sl@0
  1069
    result = (char *) TclpAlloc(size);
sl@0
  1070
    return result;
sl@0
  1071
}
sl@0
  1072
sl@0
  1073

sl@0
  1074
/*
sl@0
  1075
 *----------------------------------------------------------------------
sl@0
  1076
 *
sl@0
  1077
 * Tcl_Realloc --
sl@0
  1078
 *     Interface to TclpRealloc when TCL_MEM_DEBUG is disabled.  It does 
sl@0
  1079
 *     check that memory was actually allocated.
sl@0
  1080
 *
sl@0
  1081
 *----------------------------------------------------------------------
sl@0
  1082
 */
sl@0
  1083
sl@0
  1084
EXPORT_C char *
sl@0
  1085
Tcl_Realloc(ptr, size)
sl@0
  1086
    char *ptr;
sl@0
  1087
    unsigned int size;
sl@0
  1088
{
sl@0
  1089
    char *result;
sl@0
  1090
sl@0
  1091
    result = TclpRealloc(ptr, size);
sl@0
  1092
sl@0
  1093
    if ((result == NULL) && size) {
sl@0
  1094
	panic("unable to realloc %u bytes", size);
sl@0
  1095
    }
sl@0
  1096
    return result;
sl@0
  1097
}
sl@0
  1098
sl@0
  1099
EXPORT_C char *
sl@0
  1100
Tcl_DbCkrealloc(ptr, size, file, line)
sl@0
  1101
    char        *ptr;
sl@0
  1102
    unsigned int size;
sl@0
  1103
    CONST char  *file;
sl@0
  1104
    int          line;
sl@0
  1105
{
sl@0
  1106
    char *result;
sl@0
  1107
sl@0
  1108
    result = (char *) TclpRealloc(ptr, size);
sl@0
  1109
sl@0
  1110
    if ((result == NULL) && size) {
sl@0
  1111
        fflush(stdout);
sl@0
  1112
        panic("unable to realloc %u bytes, %s line %d", size, file, line);
sl@0
  1113
    }
sl@0
  1114
    return result;
sl@0
  1115
}
sl@0
  1116

sl@0
  1117
/*
sl@0
  1118
 *----------------------------------------------------------------------
sl@0
  1119
 *
sl@0
  1120
 * Tcl_AttemptRealloc --
sl@0
  1121
 *     Interface to TclpRealloc when TCL_MEM_DEBUG is disabled.  It does 
sl@0
  1122
 *     not check that memory was actually allocated.
sl@0
  1123
 *
sl@0
  1124
 *----------------------------------------------------------------------
sl@0
  1125
 */
sl@0
  1126
sl@0
  1127
EXPORT_C char *
sl@0
  1128
Tcl_AttemptRealloc(ptr, size)
sl@0
  1129
    char *ptr;
sl@0
  1130
    unsigned int size;
sl@0
  1131
{
sl@0
  1132
    char *result;
sl@0
  1133
sl@0
  1134
    result = TclpRealloc(ptr, size);
sl@0
  1135
    return result;
sl@0
  1136
}
sl@0
  1137
sl@0
  1138
EXPORT_C char *
sl@0
  1139
Tcl_AttemptDbCkrealloc(ptr, size, file, line)
sl@0
  1140
    char        *ptr;
sl@0
  1141
    unsigned int size;
sl@0
  1142
    CONST char  *file;
sl@0
  1143
    int          line;
sl@0
  1144
{
sl@0
  1145
    char *result;
sl@0
  1146
sl@0
  1147
    result = (char *) TclpRealloc(ptr, size);
sl@0
  1148
    return result;
sl@0
  1149
}
sl@0
  1150

sl@0
  1151
/*
sl@0
  1152
 *----------------------------------------------------------------------
sl@0
  1153
 *
sl@0
  1154
 * Tcl_Free --
sl@0
  1155
 *     Interface to TclpFree when TCL_MEM_DEBUG is disabled.  Done here
sl@0
  1156
 *     rather in the macro to keep some modules from being compiled with 
sl@0
  1157
 *     TCL_MEM_DEBUG enabled and some with it disabled.
sl@0
  1158
 *
sl@0
  1159
 *----------------------------------------------------------------------
sl@0
  1160
 */
sl@0
  1161
sl@0
  1162
EXPORT_C void
sl@0
  1163
Tcl_Free (ptr)
sl@0
  1164
    char *ptr;
sl@0
  1165
{
sl@0
  1166
    TclpFree(ptr);
sl@0
  1167
}
sl@0
  1168
sl@0
  1169
EXPORT_C int
sl@0
  1170
Tcl_DbCkfree(ptr, file, line)
sl@0
  1171
    char       *ptr;
sl@0
  1172
    CONST char *file;
sl@0
  1173
    int         line;
sl@0
  1174
{
sl@0
  1175
    TclpFree(ptr);
sl@0
  1176
    return 0;
sl@0
  1177
}
sl@0
  1178

sl@0
  1179
/*
sl@0
  1180
 *----------------------------------------------------------------------
sl@0
  1181
 *
sl@0
  1182
 * Tcl_InitMemory --
sl@0
  1183
 *     Dummy initialization for memory command, which is only available 
sl@0
  1184
 *     if TCL_MEM_DEBUG is on.
sl@0
  1185
 *
sl@0
  1186
 *----------------------------------------------------------------------
sl@0
  1187
 */
sl@0
  1188
	/* ARGSUSED */
sl@0
  1189
EXPORT_C void
sl@0
  1190
Tcl_InitMemory(interp)
sl@0
  1191
    Tcl_Interp *interp;
sl@0
  1192
{
sl@0
  1193
}
sl@0
  1194
sl@0
  1195
EXPORT_C int
sl@0
  1196
Tcl_DumpActiveMemory(fileName)
sl@0
  1197
    CONST char *fileName;
sl@0
  1198
{
sl@0
  1199
    return TCL_OK;
sl@0
  1200
}
sl@0
  1201
sl@0
  1202
EXPORT_C void
sl@0
  1203
Tcl_ValidateAllMemory(file, line)
sl@0
  1204
    CONST char *file;
sl@0
  1205
    int         line;
sl@0
  1206
{
sl@0
  1207
}
sl@0
  1208
sl@0
  1209
EXPORT_C void
sl@0
  1210
TclDumpMemoryInfo(outFile) 
sl@0
  1211
    FILE *outFile;
sl@0
  1212
{
sl@0
  1213
}
sl@0
  1214
sl@0
  1215
#endif	/* TCL_MEM_DEBUG */
sl@0
  1216

sl@0
  1217
/*
sl@0
  1218
 *---------------------------------------------------------------------------
sl@0
  1219
 *
sl@0
  1220
 * TclFinalizeMemorySubsystem --
sl@0
  1221
 *
sl@0
  1222
 *	This procedure is called to finalize all the structures that 
sl@0
  1223
 *	are used by the memory allocator on a per-process basis.
sl@0
  1224
 *
sl@0
  1225
 * Results:
sl@0
  1226
 *	None.
sl@0
  1227
 *
sl@0
  1228
 * Side effects:
sl@0
  1229
 *	This subsystem is self-initializing, since memory can be 
sl@0
  1230
 *	allocated before Tcl is formally initialized.  After this call,
sl@0
  1231
 *	this subsystem has been reset to its initial state and is 
sl@0
  1232
 *	usable again.
sl@0
  1233
 *
sl@0
  1234
 *---------------------------------------------------------------------------
sl@0
  1235
 */
sl@0
  1236
sl@0
  1237
void
sl@0
  1238
TclFinalizeMemorySubsystem()
sl@0
  1239
{
sl@0
  1240
#ifdef TCL_MEM_DEBUG
sl@0
  1241
    if (tclMemDumpFileName != NULL) {
sl@0
  1242
	Tcl_DumpActiveMemory(tclMemDumpFileName);
sl@0
  1243
    } else if (onExitMemDumpFileName != NULL) {
sl@0
  1244
	Tcl_DumpActiveMemory(onExitMemDumpFileName);
sl@0
  1245
    }
sl@0
  1246
    Tcl_MutexLock(ckallocMutexPtr);
sl@0
  1247
    if (curTagPtr != NULL) {
sl@0
  1248
	TclpFree((char *) curTagPtr);
sl@0
  1249
	curTagPtr = NULL;
sl@0
  1250
    }
sl@0
  1251
    allocHead = NULL;
sl@0
  1252
    Tcl_MutexUnlock(ckallocMutexPtr);
sl@0
  1253
#endif
sl@0
  1254
sl@0
  1255
#if USE_TCLALLOC
sl@0
  1256
    TclFinalizeAllocSubsystem(); 
sl@0
  1257
#endif
sl@0
  1258
}