alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (debug_mem.c)

This example Java source code file (debug_mem.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

byteguard, dassertmsg, dmem_clientallocate, dmem_clientcheckptr, dmem_verifyguardarea, dmutex_enter, dmutex_exit, dtrace_println, false, max_guard_bytes, memoryblockheader, memoryblocktail, memorylistlink, null

The debug_mem.c Java example source code

/*
 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#if defined(DEBUG)

#include "debug_util.h"

/* Use THIS_FILE when it is available. */
#ifndef THIS_FILE
    #define THIS_FILE __FILE__
#endif

#define DMEM_MIN(a,b)   (a) < (b) ? (a) : (b)
#define DMEM_MAX(a,b)   (a) > (b) ? (a) : (b)

typedef char byte_t;

static const byte_t ByteInited = '\xCD';
static const byte_t ByteFreed = '\xDD';
static const byte_t ByteGuard = '\xFD';

enum {
    MAX_LINENUM = 50000,        /* I certainly hope we don't have source files bigger than this */
    MAX_CHECK_BYTES = 27,       /* max bytes to check at start of block */
    MAX_GUARD_BYTES = 8,        /* size of guard areas on either side of a block */
    MAX_DECIMAL_DIGITS = 15
};

/* Debug Info Header to precede allocated block */
typedef struct MemoryBlockHeader {
    char                        filename[FILENAME_MAX+1]; /* filename where alloc occurred */
    int                         linenumber;             /* line where alloc occurred */
    size_t                      size;                   /* size of the allocation */
    int                         order;                  /* the order the block was allocated in */
    struct MemoryListLink *     listEnter;              /* pointer to the free list node */
    byte_t                      guard[MAX_GUARD_BYTES]; /* guard area for underrun check */
} MemoryBlockHeader;

/* Tail to follow allocated block */
typedef struct MemoryBlockTail {
    byte_t                      guard[MAX_GUARD_BYTES]; /* guard area overrun check */
} MemoryBlockTail;

/* Linked list of allocated memory blocks */
typedef struct MemoryListLink {
    struct MemoryListLink *     next;
    MemoryBlockHeader *         header;
    int                         freed;
} MemoryListLink;

/**************************************************
 * Global Data structures
 */
static DMemState                DMemGlobalState;
extern const DMemState *        DMemStatePtr = &DMemGlobalState;
static MemoryListLink           MemoryList = {NULL,NULL,FALSE};
static dmutex_t                 DMemMutex = NULL;

/**************************************************/

/*************************************************
 * Client callback invocation functions
 */
static void * DMem_ClientAllocate(size_t size) {
    if (DMemGlobalState.pfnAlloc != NULL) {
        return (*DMemGlobalState.pfnAlloc)(size);
    }
    return malloc(size);
}

static void DMem_ClientFree(void * ptr) {
    if (DMemGlobalState.pfnFree != NULL) {
        (*DMemGlobalState.pfnFree)(ptr);
    }
    free(ptr);
}

static dbool_t DMem_ClientCheckPtr(void * ptr, size_t size) {
    if (DMemGlobalState.pfnCheckPtr != NULL) {
        return (*DMemGlobalState.pfnCheckPtr)(ptr, size);
    }
    return ptr != NULL;
}

/**************************************************/

/*************************************************
 * Debug Memory Manager implementation
 */

static MemoryListLink * DMem_TrackBlock(MemoryBlockHeader * header) {
    MemoryListLink *    link;

    link = (MemoryListLink *)DMem_ClientAllocate(sizeof(MemoryListLink));
    if (link != NULL) {
        link->header = header;
        link->header->listEnter = link;
        link->next = MemoryList.next;
        link->freed = FALSE;
        MemoryList.next = link;
    }

    return link;
}

static int DMem_VerifyGuardArea(const byte_t * area) {
    int         nbyte;

    for ( nbyte = 0; nbyte < MAX_GUARD_BYTES; nbyte++ ) {
        if (area[nbyte] != ByteGuard) {
            return FALSE;
        }
    }
    return TRUE;
}

static void DMem_VerifyHeader(MemoryBlockHeader * header) {
    DASSERTMSG( DMem_ClientCheckPtr(header, sizeof(MemoryBlockHeader)), "Invalid header" );
    DASSERTMSG( DMem_VerifyGuardArea(header->guard), "Header corruption, possible underwrite" );
    DASSERTMSG( header->linenumber > 0 && header->linenumber < MAX_LINENUM, "Header corruption, bad line number" );
    DASSERTMSG( header->size <= DMemGlobalState.biggestBlock, "Header corruption, block size is too large");
    DASSERTMSG( header->order <= DMemGlobalState.totalAllocs, "Header corruption, block order out of range");
}

static void DMem_VerifyTail(MemoryBlockTail * tail) {
    DASSERTMSG( DMem_ClientCheckPtr(tail, sizeof(MemoryBlockTail)), "Tail corruption, invalid pointer");
    DASSERTMSG( DMem_VerifyGuardArea(tail->guard), "Tail corruption, possible overwrite" );
}

static MemoryBlockHeader * DMem_VerifyBlock(void * memptr) {
    MemoryBlockHeader * header;
    MemoryBlockTail *   tail;

    /* check if the pointer is valid */
    DASSERTMSG( DMem_ClientCheckPtr(memptr, 1), "Invalid pointer");

    /* check if the block header is valid */
    header = (MemoryBlockHeader *)((byte_t *)memptr - sizeof(MemoryBlockHeader));
    DMem_VerifyHeader(header);
    /* check that the memory itself is valid */
    DASSERTMSG( DMem_ClientCheckPtr(memptr, DMEM_MIN(MAX_CHECK_BYTES,header->size)), "Block memory invalid" );
    /* check that the pointer to the alloc list is valid */
    DASSERTMSG( DMem_ClientCheckPtr(header->listEnter, sizeof(MemoryListLink)), "Header corruption, alloc list pointer invalid" );
    /* check the tail of the block for overruns */
    tail = (MemoryBlockTail *) ( (byte_t *)memptr + header->size );
    DMem_VerifyTail(tail);

    return header;
}

static MemoryBlockHeader * DMem_GetHeader(void * memptr) {
    MemoryBlockHeader * header = DMem_VerifyBlock(memptr);
    return header;
}

/*
 * Should be called before any other DMem_XXX function
 */
void DMem_Initialize() {
    DMemMutex = DMutex_Create();
    DMutex_Enter(DMemMutex);
    DMemGlobalState.pfnAlloc = NULL;
    DMemGlobalState.pfnFree = NULL;
    DMemGlobalState.pfnCheckPtr = NULL;
    DMemGlobalState.biggestBlock = 0;
    DMemGlobalState.maxHeap = INT_MAX;
    DMemGlobalState.totalHeapUsed = 0;
    DMemGlobalState.failNextAlloc = FALSE;
    DMemGlobalState.totalAllocs = 0;
    DMutex_Exit(DMemMutex);
}

void DMem_Shutdown() {
    DMutex_Destroy(DMemMutex);
}
/*
 * Allocates a block of memory, reserving extra space at the start and end of the
 * block to store debug info on where the block was allocated, it's size, and
 * 'guard' areas to catch overwrite/underwrite bugs
 */
void * DMem_AllocateBlock(size_t size, const char * filename, int linenumber) {
    MemoryBlockHeader * header;
    MemoryBlockTail *   tail;
    size_t              debugBlockSize;
    byte_t *            memptr = NULL;

    DMutex_Enter(DMemMutex);
    if (DMemGlobalState.failNextAlloc) {
    /* force an allocation failure if so ordered */
        DMemGlobalState.failNextAlloc = FALSE; /* reset flag */
        goto Exit;
    }

    /* allocate a block large enough to hold extra debug info */
    debugBlockSize = sizeof(MemoryBlockHeader) + size + sizeof(MemoryBlockTail);
    header = (MemoryBlockHeader *)DMem_ClientAllocate(debugBlockSize);
    if (header == NULL) {
        goto Exit;
    }

    /* add block to list of allocated memory */
    header->listEnter = DMem_TrackBlock(header);
    if ( header->listEnter == NULL ) {
        goto Exit;
    }

    /* store size of requested block */
    header->size = size;
    /* update maximum block size */
    DMemGlobalState.biggestBlock = DMEM_MAX(header->size, DMemGlobalState.biggestBlock);
    /* update used memory total */
    DMemGlobalState.totalHeapUsed += header->size;
    /* store filename and linenumber where allocation routine was called */
    strncpy(header->filename, filename, FILENAME_MAX);
    header->linenumber = linenumber;
    /* store the order the block was allocated in */
    header->order = DMemGlobalState.totalAllocs++;
    /* initialize memory to a recognizable 'inited' value */
    memptr = (byte_t *)header + sizeof(MemoryBlockHeader);
    memset(memptr, ByteInited, size);
    /* put guard area before block */
    memset(header->guard, ByteGuard, MAX_GUARD_BYTES);
    /* put guard area after block */
    tail = (MemoryBlockTail *)(memptr + size);
    memset(tail->guard, ByteGuard, MAX_GUARD_BYTES);

Exit:
    DMutex_Exit(DMemMutex);
    return memptr;
}

/*
 * Frees block of memory allocated with DMem_AllocateBlock
 */
void DMem_FreeBlock(void * memptr) {
    MemoryBlockHeader * header;

    DMutex_Enter(DMemMutex);
    if ( memptr == NULL) {
        goto Exit;
    }

    /* get the debug block header preceding the allocated memory */
    header = DMem_GetHeader(memptr);
    /* fill memory with recognizable 'freed' value */
    memset(memptr, ByteFreed, header->size);
    /* mark block as freed */
    header->listEnter->freed = TRUE;
    /* update used memory total */
    DMemGlobalState.totalHeapUsed -= header->size;
Exit:
    DMutex_Exit(DMemMutex);
}

static void DMem_DumpHeader(MemoryBlockHeader * header) {
    char        report[FILENAME_MAX+MAX_DECIMAL_DIGITS*3+1];
    static const char * reportFormat =
        "file:  %s, line %d\n"
        "size:  %d bytes\n"
        "order: %d\n"
        "-------";

    DMem_VerifyHeader(header);
    sprintf(report, reportFormat, header->filename, header->linenumber, header->size, header->order);
    DTRACE_PRINTLN(report);
}

/*
 * Call this function at shutdown time to report any leaked blocks
 */
void DMem_ReportLeaks() {
    MemoryListLink *    link;

    DMutex_Enter(DMemMutex);

    /* Force memory leaks to be output regardless of trace settings */
    DTrace_EnableFile(THIS_FILE, TRUE);
    DTRACE_PRINTLN("--------------------------");
    DTRACE_PRINTLN("Debug Memory Manager Leaks");
    DTRACE_PRINTLN("--------------------------");

    /* walk through allocated list and dump any blocks not marked as freed */
    link = MemoryList.next;
    while (link != NULL) {
        if ( !link->freed ) {
            DMem_DumpHeader(link->header);
        }
        link = link->next;
    }

    DMutex_Exit(DMemMutex);
}

void DMem_SetAllocCallback( DMEM_ALLOCFN pfn ) {
    DMutex_Enter(DMemMutex);
    DMemGlobalState.pfnAlloc = pfn;
    DMutex_Exit(DMemMutex);
}

void DMem_SetFreeCallback( DMEM_FREEFN pfn ) {
    DMutex_Enter(DMemMutex);
    DMemGlobalState.pfnFree = pfn;
    DMutex_Exit(DMemMutex);
}

void DMem_SetCheckPtrCallback( DMEM_CHECKPTRFN pfn ) {
    DMutex_Enter(DMemMutex);
    DMemGlobalState.pfnCheckPtr = pfn;
    DMutex_Exit(DMemMutex);
}

void DMem_DisableMutex() {
    DMemMutex = NULL;
}

#endif  /* defined(DEBUG) */

/* The following line is only here to prevent compiler warnings
 * on release (non-debug) builds
 */
static int dummyVariable = 0;

Other Java examples (source code examples)

Here is a short list of links related to this Java debug_mem.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.