Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/awt/debug/debug_mem.c
38918 views
/*1* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#if defined(DEBUG)2627#include "debug_util.h"2829/* Use THIS_FILE when it is available. */30#ifndef THIS_FILE31#define THIS_FILE __FILE__32#endif3334#define DMEM_MIN(a,b) (a) < (b) ? (a) : (b)35#define DMEM_MAX(a,b) (a) > (b) ? (a) : (b)3637typedef char byte_t;3839static const byte_t ByteInited = '\xCD';40static const byte_t ByteFreed = '\xDD';41static const byte_t ByteGuard = '\xFD';4243enum {44MAX_LINENUM = 50000, /* I certainly hope we don't have source files bigger than this */45MAX_CHECK_BYTES = 27, /* max bytes to check at start of block */46MAX_GUARD_BYTES = 8, /* size of guard areas on either side of a block */47MAX_DECIMAL_DIGITS = 1548};4950/* Debug Info Header to precede allocated block */51typedef struct MemoryBlockHeader {52char filename[FILENAME_MAX+1]; /* filename where alloc occurred */53int linenumber; /* line where alloc occurred */54size_t size; /* size of the allocation */55int order; /* the order the block was allocated in */56struct MemoryListLink * listEnter; /* pointer to the free list node */57byte_t guard[MAX_GUARD_BYTES]; /* guard area for underrun check */58} MemoryBlockHeader;5960/* Tail to follow allocated block */61typedef struct MemoryBlockTail {62byte_t guard[MAX_GUARD_BYTES]; /* guard area overrun check */63} MemoryBlockTail;6465/* Linked list of allocated memory blocks */66typedef struct MemoryListLink {67struct MemoryListLink * next;68MemoryBlockHeader * header;69int freed;70} MemoryListLink;7172/**************************************************73* Global Data structures74*/75static DMemState DMemGlobalState;76extern const DMemState * DMemStatePtr = &DMemGlobalState;77static MemoryListLink MemoryList = {NULL,NULL,FALSE};78static dmutex_t DMemMutex = NULL;7980/**************************************************/8182/*************************************************83* Client callback invocation functions84*/85static void * DMem_ClientAllocate(size_t size) {86if (DMemGlobalState.pfnAlloc != NULL) {87return (*DMemGlobalState.pfnAlloc)(size);88}89return malloc(size);90}9192static void DMem_ClientFree(void * ptr) {93if (DMemGlobalState.pfnFree != NULL) {94(*DMemGlobalState.pfnFree)(ptr);95}96free(ptr);97}9899static dbool_t DMem_ClientCheckPtr(void * ptr, size_t size) {100if (DMemGlobalState.pfnCheckPtr != NULL) {101return (*DMemGlobalState.pfnCheckPtr)(ptr, size);102}103return ptr != NULL;104}105106/**************************************************/107108/*************************************************109* Debug Memory Manager implementation110*/111112static MemoryListLink * DMem_TrackBlock(MemoryBlockHeader * header) {113MemoryListLink * link;114115link = (MemoryListLink *)DMem_ClientAllocate(sizeof(MemoryListLink));116if (link != NULL) {117link->header = header;118link->header->listEnter = link;119link->next = MemoryList.next;120link->freed = FALSE;121MemoryList.next = link;122}123124return link;125}126127static int DMem_VerifyGuardArea(const byte_t * area) {128int nbyte;129130for ( nbyte = 0; nbyte < MAX_GUARD_BYTES; nbyte++ ) {131if (area[nbyte] != ByteGuard) {132return FALSE;133}134}135return TRUE;136}137138static void DMem_VerifyHeader(MemoryBlockHeader * header) {139DASSERTMSG( DMem_ClientCheckPtr(header, sizeof(MemoryBlockHeader)), "Invalid header" );140DASSERTMSG( DMem_VerifyGuardArea(header->guard), "Header corruption, possible underwrite" );141DASSERTMSG( header->linenumber > 0 && header->linenumber < MAX_LINENUM, "Header corruption, bad line number" );142DASSERTMSG( header->size <= DMemGlobalState.biggestBlock, "Header corruption, block size is too large");143DASSERTMSG( header->order <= DMemGlobalState.totalAllocs, "Header corruption, block order out of range");144}145146static void DMem_VerifyTail(MemoryBlockTail * tail) {147DASSERTMSG( DMem_ClientCheckPtr(tail, sizeof(MemoryBlockTail)), "Tail corruption, invalid pointer");148DASSERTMSG( DMem_VerifyGuardArea(tail->guard), "Tail corruption, possible overwrite" );149}150151static MemoryBlockHeader * DMem_VerifyBlock(void * memptr) {152MemoryBlockHeader * header;153MemoryBlockTail * tail;154155/* check if the pointer is valid */156DASSERTMSG( DMem_ClientCheckPtr(memptr, 1), "Invalid pointer");157158/* check if the block header is valid */159header = (MemoryBlockHeader *)((byte_t *)memptr - sizeof(MemoryBlockHeader));160DMem_VerifyHeader(header);161/* check that the memory itself is valid */162DASSERTMSG( DMem_ClientCheckPtr(memptr, DMEM_MIN(MAX_CHECK_BYTES,header->size)), "Block memory invalid" );163/* check that the pointer to the alloc list is valid */164DASSERTMSG( DMem_ClientCheckPtr(header->listEnter, sizeof(MemoryListLink)), "Header corruption, alloc list pointer invalid" );165/* check the tail of the block for overruns */166tail = (MemoryBlockTail *) ( (byte_t *)memptr + header->size );167DMem_VerifyTail(tail);168169return header;170}171172static MemoryBlockHeader * DMem_GetHeader(void * memptr) {173MemoryBlockHeader * header = DMem_VerifyBlock(memptr);174return header;175}176177/*178* Should be called before any other DMem_XXX function179*/180void DMem_Initialize() {181DMemMutex = DMutex_Create();182DMutex_Enter(DMemMutex);183DMemGlobalState.pfnAlloc = NULL;184DMemGlobalState.pfnFree = NULL;185DMemGlobalState.pfnCheckPtr = NULL;186DMemGlobalState.biggestBlock = 0;187DMemGlobalState.maxHeap = INT_MAX;188DMemGlobalState.totalHeapUsed = 0;189DMemGlobalState.failNextAlloc = FALSE;190DMemGlobalState.totalAllocs = 0;191DMutex_Exit(DMemMutex);192}193194void DMem_Shutdown() {195DMutex_Destroy(DMemMutex);196}197/*198* Allocates a block of memory, reserving extra space at the start and end of the199* block to store debug info on where the block was allocated, it's size, and200* 'guard' areas to catch overwrite/underwrite bugs201*/202void * DMem_AllocateBlock(size_t size, const char * filename, int linenumber) {203MemoryBlockHeader * header;204MemoryBlockTail * tail;205size_t debugBlockSize;206byte_t * memptr = NULL;207208DMutex_Enter(DMemMutex);209if (DMemGlobalState.failNextAlloc) {210/* force an allocation failure if so ordered */211DMemGlobalState.failNextAlloc = FALSE; /* reset flag */212goto Exit;213}214215/* allocate a block large enough to hold extra debug info */216debugBlockSize = sizeof(MemoryBlockHeader) + size + sizeof(MemoryBlockTail);217header = (MemoryBlockHeader *)DMem_ClientAllocate(debugBlockSize);218if (header == NULL) {219goto Exit;220}221222/* add block to list of allocated memory */223header->listEnter = DMem_TrackBlock(header);224if ( header->listEnter == NULL ) {225goto Exit;226}227228/* store size of requested block */229header->size = size;230/* update maximum block size */231DMemGlobalState.biggestBlock = DMEM_MAX(header->size, DMemGlobalState.biggestBlock);232/* update used memory total */233DMemGlobalState.totalHeapUsed += header->size;234/* store filename and linenumber where allocation routine was called */235strncpy(header->filename, filename, FILENAME_MAX);236header->linenumber = linenumber;237/* store the order the block was allocated in */238header->order = DMemGlobalState.totalAllocs++;239/* initialize memory to a recognizable 'inited' value */240memptr = (byte_t *)header + sizeof(MemoryBlockHeader);241memset(memptr, ByteInited, size);242/* put guard area before block */243memset(header->guard, ByteGuard, MAX_GUARD_BYTES);244/* put guard area after block */245tail = (MemoryBlockTail *)(memptr + size);246memset(tail->guard, ByteGuard, MAX_GUARD_BYTES);247248Exit:249DMutex_Exit(DMemMutex);250return memptr;251}252253/*254* Frees block of memory allocated with DMem_AllocateBlock255*/256void DMem_FreeBlock(void * memptr) {257MemoryBlockHeader * header;258259DMutex_Enter(DMemMutex);260if ( memptr == NULL) {261goto Exit;262}263264/* get the debug block header preceding the allocated memory */265header = DMem_GetHeader(memptr);266/* fill memory with recognizable 'freed' value */267memset(memptr, ByteFreed, header->size);268/* mark block as freed */269header->listEnter->freed = TRUE;270/* update used memory total */271DMemGlobalState.totalHeapUsed -= header->size;272Exit:273DMutex_Exit(DMemMutex);274}275276static void DMem_DumpHeader(MemoryBlockHeader * header) {277char report[FILENAME_MAX+MAX_DECIMAL_DIGITS*3+1];278static const char * reportFormat =279"file: %s, line %d\n"280"size: %d bytes\n"281"order: %d\n"282"-------";283284DMem_VerifyHeader(header);285sprintf(report, reportFormat, header->filename, header->linenumber, header->size, header->order);286DTRACE_PRINTLN(report);287}288289/*290* Call this function at shutdown time to report any leaked blocks291*/292void DMem_ReportLeaks() {293MemoryListLink * link;294295DMutex_Enter(DMemMutex);296297/* Force memory leaks to be output regardless of trace settings */298DTrace_EnableFile(THIS_FILE, TRUE);299DTRACE_PRINTLN("--------------------------");300DTRACE_PRINTLN("Debug Memory Manager Leaks");301DTRACE_PRINTLN("--------------------------");302303/* walk through allocated list and dump any blocks not marked as freed */304link = MemoryList.next;305while (link != NULL) {306if ( !link->freed ) {307DMem_DumpHeader(link->header);308}309link = link->next;310}311312DMutex_Exit(DMemMutex);313}314315void DMem_SetAllocCallback( DMEM_ALLOCFN pfn ) {316DMutex_Enter(DMemMutex);317DMemGlobalState.pfnAlloc = pfn;318DMutex_Exit(DMemMutex);319}320321void DMem_SetFreeCallback( DMEM_FREEFN pfn ) {322DMutex_Enter(DMemMutex);323DMemGlobalState.pfnFree = pfn;324DMutex_Exit(DMemMutex);325}326327void DMem_SetCheckPtrCallback( DMEM_CHECKPTRFN pfn ) {328DMutex_Enter(DMemMutex);329DMemGlobalState.pfnCheckPtr = pfn;330DMutex_Exit(DMemMutex);331}332333void DMem_DisableMutex() {334DMemMutex = NULL;335}336337#endif /* defined(DEBUG) */338339/* The following line is only here to prevent compiler warnings340* on release (non-debug) builds341*/342static int dummyVariable = 0;343344345