/* dvdisaster: Additional error correction for optical media. * Copyright (C) 2004-2009 Carsten Gnoerlich. * Project home page: http://www.dvdisaster.com * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, * or direct your browser at http://www.gnu.org. */ #define _GNU_SOURCE #if !defined(SYS_FREEBSD) && !defined(SYS_DARWIN) /* FreeBSD declares malloc() in stdlib.h */ #include #endif #include #include #include #include #include #include /* * We're not pulling in dvdisaster.h on purpose... */ void Stop(char*, ...); /*** *** Special routines for keeping track of memory allocation. *** * memtrack.c currently uses malloc() and friends. * This is probably a bad idea for those operating systems where g_malloc() * and malloc() are different and not compatible. * We must keep an eye on that. */ /*** *** Keeping track of allocated pointers. ***/ /* * A structure containing info about each pointer which was * produced through our memory allocation routines. */ typedef struct _memchunk { void *ptr; /* allocated memory chunk */ int size; /* size of chunk */ char *file; /* source file this was allocated in */ int line; /* line number of source file */ } memchunk; /* * Since we're compiled in optionally, * we do not use the common Closure struct. */ static struct _memchunk **ptrhash[64]; /* 64 buckets of memory chunks */ static int phCnt[64]; static int phMax[64]; static int currentAllocation; /* current memory allocation */ static int peakAllocation; /* maximum allocation */ /* * Remember an allocated pointer. */ void remember(void *ptr, int size, char *file, int line) { memchunk *mc; int hash_idx; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock(&mutex); hash_idx = (((long)ptr)>>3)&63; if(phCnt[hash_idx] >= phMax[hash_idx]) { if(!phMax[hash_idx]) phMax[hash_idx] = 16; else phMax[hash_idx] *= 2; if(!(ptrhash[hash_idx] = realloc(ptrhash[hash_idx], sizeof(memchunk*)*phMax[hash_idx]))) Stop("can't realloc memchunk hashtable"); } if(!(mc=malloc(sizeof(memchunk)))) Stop("can't alloc memchunk"); ptrhash[hash_idx][phCnt[hash_idx]++] = mc; mc->ptr = ptr; mc->size = size; mc->file = file; mc->line = line; currentAllocation += size; if(currentAllocation > peakAllocation) peakAllocation = currentAllocation; g_static_mutex_unlock(&mutex); } /* * Remove a remembered pointer from the hash bucket. */ int forget(void *ptr) { static GStaticMutex mutex = G_STATIC_MUTEX_INIT; memchunk **ptrlist; int hash_idx; int i; g_static_mutex_lock(&mutex); hash_idx = (((long)ptr)>>3)&63; ptrlist = ptrhash[hash_idx]; for(i=0; iptr==ptr) { currentAllocation -= ptrlist[i]->size; free(ptrlist[i]); phCnt[hash_idx]--; if(phCnt[hash_idx] > 0) ptrlist[i] = ptrlist[phCnt[hash_idx]]; g_static_mutex_unlock(&mutex); return 0; } g_static_mutex_unlock(&mutex); return 1; } /* * Print the contents of the ptrlist. */ static void print_ptr(memchunk *mc, int size) { char strbuf[16]; char *ptr = (char*)mc->ptr; int j,maxlen; if(mc->size < size) maxlen = mc->size; else maxlen = size; for(j=0; j<15; j++) { if(ptr[j]<32) break; strbuf[j] = ptr[j]; } if(j) { strbuf[j]=0; g_printf("Address 0x%lx (\"%s\"), %d bytes, from %s, line %d\n", (unsigned long)mc->ptr,strbuf,mc->size,mc->file,mc->line); } else g_printf("Address 0x%lx (binary data), %d bytes, from %s, line %d\n", (unsigned long)mc->ptr,mc->size,mc->file,mc->line); } static void print_ptrs(char *msg) { int bucket,i,n=0; g_printf(msg); for(bucket=0; bucket<64; bucket++) for(i=0; i