/* * Part: Memory management framework. This framework is used to * find any memory leak. * * Version: $Id: memory.c,v 1.1.11 2005/03/01 01:22:13 acassen Exp $ * * Authors: Alexandre Cassen, * Jan Holmberg, * * 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. * * 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. * * Copyright (C) 2001-2005 Alexandre Cassen, */ #include "memory.h" /* Global var */ unsigned long mem_allocated; /* Total memory used in Bytes */ void * xalloc(unsigned long size) { void *mem; if ((mem = malloc(size))) mem_allocated += size; return mem; } void * zalloc(unsigned long size) { void *mem; if ((mem = malloc(size))) { memset(mem, 0, size); mem_allocated += size; } return mem; } void xfree(void *p) { mem_allocated -= sizeof (p); free(p); p = NULL; } /* * Memory management. in debug mode, * help finding eventual memory leak. * Allocation memory types manipulated are : * * +type+--------meaning--------+ * ! 0 ! Free slot ! * ! 1 ! Overrun ! * ! 2 ! free null ! * ! 3 ! realloc null ! * ! 4 ! Not previus allocated ! * ! 8 ! Last free list ! * ! 9 ! Allocated ! * +----+-----------------------+ * * global variabel debug bit 9 ( 512 ) used to * flag some memory error. * */ #ifdef _DEBUG_ typedef struct { int type; int line; char *func; char *file; void *ptr; unsigned long size; long csum; } MEMCHECK; /* Last free pointers */ static MEMCHECK free_list[256]; static MEMCHECK alloc_list[MAX_ALLOC_LIST]; static int number_alloc_list = 0; static int n = 0; /* Alloc list pointer */ static int f = 0; /* Free list pointer */ void * dbg_malloc(unsigned long size, char *file, char *function, int line) { void *buf; int i = 0; long check; buf = zalloc(size + sizeof (long)); check = 0xa5a5 + size; *(long *) ((char *) buf + size) = check; while (i < number_alloc_list) { if (alloc_list[i].type == 0) break; i++; } if (i == number_alloc_list) number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = size; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].csum = check; alloc_list[i].type = 9; if (debug & 1) printf("zalloc[%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, size, file, line, function); n++; return buf; } char * dbg_strdup(char *str, char *file, char *function, int line) { void *buf; int i = 0; long check; long size; size = strlen(str) + 1; buf = zalloc(size + sizeof (long)); strcat(buf, str); check = 0xa5a5 + size; *(long *) ((char *) buf + size) = check; while (i < number_alloc_list) { if (alloc_list[i].type == 0) break; i++; } if (i == number_alloc_list) number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = size; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].csum = check; alloc_list[i].type = 9; if (debug & 1) printf("strdup[%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, size, file, line, function); n++; return buf; } /* Display a buffer into a HEXA formated output */ static void dump_buffer(char *buff, int count) { int i, j, c; int printnext = 1; if (count % 16) c = count + (16 - count % 16); else c = count; for (i = 0; i < c; i++) { if (printnext) { printnext--; printf("%.4x ", i & 0xffff); } if (i < count) printf("%3.2x", buff[i] & 0xff); else printf(" "); if (!((i + 1) % 8)) { if ((i + 1) % 16) printf(" -"); else { printf(" "); for (j = i - 15; j <= i; j++) if (j < count) { if ((buff[j] & 0xff) >= 0x20 && (buff[j] & 0xff) <= 0x7e) printf("%c", buff[j] & 0xff); else printf("."); } else printf(" "); printf("\n"); printnext = 1; } } } } int dbg_free(void *buffer, char *file, char *function, int line) { int i = 0; void *buf; /* If nullpointer remember */ if (buffer == NULL) { i = number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buffer; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 2; if (debug & 1) printf("free NULL in %s, %3d, %s\n", file, line, function); debug |= 512; /* Memory Error detect */ return n; } else buf = buffer; while (i < number_alloc_list) { if (alloc_list[i].type == 9 && alloc_list[i].ptr == buf) { if (* ((long *) ((char *) alloc_list[i].ptr + alloc_list[i].size)) == alloc_list[i].csum) alloc_list[i].type = 0; /* Release */ else { alloc_list[i].type = 1; /* Overrun */ if (debug & 1) { printf("free corrupt, buffer overrun [%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, alloc_list[i].size, file, line, function); dump_buffer(alloc_list[i].ptr, alloc_list[i].size + sizeof (long)); printf("Check_sum\n"); dump_buffer((char *) &alloc_list[i].csum, sizeof(long)); debug |= 512; /* Memory Error detect */ } } break; } i++; } /* Not found */ if (i == number_alloc_list) { printf("Free ERROR %p\n", buffer); number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 4; debug |= 512; return n; } if (buffer != NULL) xfree(buffer); if (debug & 1) printf("free [%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, alloc_list[i].size, file, line, function); free_list[f].file = file; free_list[f].line = line; free_list[f].func = function; free_list[f].ptr = buffer; free_list[f].type = 8; free_list[f].csum = i; /* Using this field for row id */ f++; f &= 255; n--; return n; } void dbg_free_final(char *banner) { unsigned int sum = 0, overrun = 0, badptr = 0; int i, j; i = 0; printf("\n---[ Memory dump for (%s)]---\n\n", banner); while (i < number_alloc_list) { switch (alloc_list[i].type) { case 3: badptr++; printf ("null pointer to realloc(nil,%ld)! at %s, %3d, %s\n", alloc_list[i].size, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 4: badptr++; printf ("pointer not found in table to free(%p) [%3d:%3d], at %s, %3d, %s\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); for (j = 0; j < 256; j++) if (free_list[j].ptr == alloc_list[i].ptr) if (free_list[j].type == 8) printf (" -> pointer already released at [%3d:%3d], at %s, %3d, %s\n", (int) free_list[j].csum, number_alloc_list, free_list[j].file, free_list[j].line, free_list[j].func); break; case 2: badptr++; printf("null pointer to free(nil)! at %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 1: overrun++; printf("%p [%3d:%3d], %4ld buffer overrun!:\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].size); printf(" --> source of malloc: %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 9: sum += alloc_list[i].size; printf("%p [%3d:%3d], %4ld not released!:\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].size); printf(" --> source of malloc: %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; } i++; } printf("\n\n---[ Memory dump summary for (%s) ]---\n", banner); printf("Total number of bytes not freed...: %d\n", sum); printf("Number of entries not freed.......: %d\n", n); printf("Maximum allocated entries.........: %d\n", number_alloc_list); printf("Number of bad entries.............: %d\n", badptr); printf("Number of buffer overrun..........: %d\n\n", overrun); if (sum || n || badptr || overrun) printf("=> Program seems to have some memory problem !!!\n\n"); else printf("=> Program seems to be memory allocation safe...\n\n"); } void * dbg_realloc(void *buffer, unsigned long size, char *file, char *function, int line) { int i = 0; void *buf, *buf2; long check; if (buffer == NULL) { printf("realloc %p %s, %3d %s\n", buffer, file, line, function); i = number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = NULL; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 3; return dbg_malloc(size, file, function, line); } buf = buffer; while (i < number_alloc_list) { if (alloc_list[i].ptr == buf) { buf = alloc_list[i].ptr; break; } i++; } /* not found */ if (i == number_alloc_list) { printf("realloc ERROR no matching zalloc %p \n", buffer); number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 9; debug |= 512; /* Memory Error detect */ return NULL; } buf2 = ((char *) buf) + alloc_list[i].size; if (*(long *) (buf2) != alloc_list[i].csum) { alloc_list[i].type = 1; debug |= 512; /* Memory Error detect */ } buf = realloc(buffer, size + sizeof (long)); check = 0xa5a5 + size; *(long *) ((char *) buf + size) = check; alloc_list[i].csum = check; if (debug & 1) printf("realloc [%3d:%3d] %p, %4ld %s %d %s -> %p %4ld %s %d %s\n", i, number_alloc_list, alloc_list[i].ptr, alloc_list[i].size, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func, buf, size, file, line, function); alloc_list[i].ptr = buf; alloc_list[i].size = size; alloc_list[i].file = file; alloc_list[i].line = line; alloc_list[i].func = function; return buf; } #endif