?? memory.c
字號:
/*
* FILE: memory.c
* AUTHORS: Isidor Kouvelas / Colin Perkins / Mark Handley / Orion Hodson
*
* $Revision: 1.5 $
* $Date: 2002/06/12 17:37:25 $
*
* Copyright (c) 1995-2000 University College London
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Science
* Department at University College London
* 4. Neither the name of the University nor of the Department may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config_unix.h"
#include "config_win32.h"
#include "debug.h"
#include "memory.h"
#include "util.h"
#ifdef DEBUG_MEM
/* Custom memory routines are here, down to #else, defaults follow */
#define MAX_ADDRS 65536
#define MAGIC_MEMORY 0xdeadbeef
#define MAGIC_MEMORY_SIZE 4
/* Allocated block format is:
* <chk_header> <memory chunk...> <trailing magic number>
*/
typedef struct {
uint32_t key; /* Original allocation number */
uint32_t size; /* Size of allocation requested */
uint32_t pad; /* Alignment padding to 8 bytes */
uint32_t magic; /* Magic number */
} chk_header;
typedef struct s_alloc_blk {
uint32_t key; /* Key in table (ascending) */
chk_header *addr;
char *filen; /* file where allocated */
int line; /* line where allocated */
size_t length; /* size of allocation */
int blen; /* size passed to block_alloc (if relevent) */
int est; /* time last touched in order of all allocation and reclaims */
} alloc_blk;
/* Table is ordered by key */
static alloc_blk mem_item[MAX_ADDRS];
static int naddr = 0; /* number of allocations */
static int tick = 1; /* xmemchk assumes this is one, do not change without checking why */
static int init = 0;
/**
* xdoneinit:
* @void:
*
* Marks end of an applications initialization period. For media
* applications with real-time data transfer it's sometimes helpful to
* distinguish between memory allocated during application
* initialization and when application is running.
**/
void xdoneinit(void)
{
init = tick++;
}
extern int chk_header_okay(const chk_header *ch);
int chk_header_okay(const chk_header *ch)
{
const uint8_t *tm; /* tail magic */
ASSERT(ch != NULL);
if (ch->key == MAGIC_MEMORY) {
fprintf(stderr, "ERROR: freed unit being checked\n");
abort();
}
tm = (const uint8_t*)ch;
tm += sizeof(chk_header) + ch->size;
if (ch->magic != MAGIC_MEMORY) {
fprintf(stderr, "ERROR: memory underrun\n");
abort();
return FALSE;
} else if (memcmp(tm, &ch->magic, MAGIC_MEMORY_SIZE)) {
fprintf(stderr, "ERROR: memory overrun\n");
abort();
return FALSE;
}
return TRUE;
}
static int mem_key_cmp(const void *a, const void *b) {
const alloc_blk *g, *h;
g = (const alloc_blk*)a;
h = (const alloc_blk*)b;
if (g->key < h->key) {
return -1;
} else if (g->key > h->key) {
return +1;
}
return 0;
}
static alloc_blk *mem_item_find(uint32_t key) {
void *p;
alloc_blk t;
t.key = key;
p = bsearch((const void*)&t, mem_item, naddr, sizeof(alloc_blk), mem_key_cmp);
return (alloc_blk*)p;
}
/**
* xmemchk:
* @void:
*
* Check for bounds overruns in all memory allocated with xmalloc(),
* xrealloc(), and xstrdup(). Information on corrupted blocks is
* rendered on the standard error stream. This includes where the
* block was allocated, the size of the block, and the number of
* allocations made since the block was created.
**/
void xmemchk(void)
{
uint32_t last_key;
chk_header *ch;
int i;
if (naddr > MAX_ADDRS) {
fprintf(stderr, "ERROR: Too many addresses for xmemchk()!\n");
abort();
}
last_key = 0;
for (i = 0; i < naddr; i++) {
/* Check for table corruption */
if (mem_item[i].key < last_key) {
fprintf(stderr, "Memory table keys out of order - fatal error");
abort();
}
last_key = mem_item[i].key;
if (mem_item[i].addr == NULL) {
fprintf(stderr, "Memory table entry reference null block - fatal error");
abort();
}
if (mem_item[i].filen == NULL) {
fprintf(stderr, "Memory table filename missing - fatal error");
abort();
}
if ((size_t) strlen(mem_item[i].filen) != mem_item[i].length) {
fprintf(stderr, "Memory table filename length corrupted - fatal error");
abort();
}
/* Check memory */
ch = mem_item[i].addr;
if (chk_header_okay(ch) == FALSE) {
/* Chk header display which side has gone awry */
fprintf(stderr, "Memory check failed!\n");
fprintf(stderr, "addr: %p", mem_item[i].addr);
fprintf(stderr, " size: %6d", ch->size);
fprintf(stderr, " age: %6d", tick - mem_item[i].est);
fprintf(stderr, " file: %s", mem_item[i].filen);
fprintf(stderr, " line: %d", mem_item[i].line);
fprintf(stderr, "\n");
abort();
}
}
}
static int
alloc_blk_cmp_origin(const void *vab1, const void *vab2)
{
const alloc_blk *ab1, *ab2;
int sc;
ab1 = (const alloc_blk*)vab1;
ab2 = (const alloc_blk*)vab2;
if (ab1->filen == NULL || ab2->filen == NULL) {
if (ab1->filen == NULL && ab2->filen == NULL) {
return 0;
} else if (ab1->filen == NULL) {
return +1;
} else /* (ab2->filen == NULL)*/ {
return -1;
}
}
sc = strcmp(ab1->filen, ab2->filen);
if (sc == 0) {
if (ab1->line > ab2->line) {
return +1;
} else if (ab1->line == ab2->line) {
return 0;
} else /* (ab1->line < ab2->line) */{
return -1;
}
}
return sc;
}
static int
alloc_blk_cmp_est(const void *vab1, const void *vab2)
{
const alloc_blk *ab1, *ab2;
ab1 = (const alloc_blk*)vab1;
ab2 = (const alloc_blk*)vab2;
if (ab1->est > ab2->est) {
return +1;
} else if (ab1->est == ab2->est) {
return 0;
} else {
return -1;
}
}
/**
* xmemdmp:
* @void:
*
* Dumps the address, size, age, and point of allocation in code.
*
**/
void
xmemdmp(void)
{
int i;
block_release_all();
if (naddr > MAX_ADDRS) {
printf("ERROR: Too many addresses for xmemdmp()!\n");
abort();
}
qsort(mem_item, naddr, sizeof(mem_item[0]), alloc_blk_cmp_est);
for (i=0; i<naddr; i++) {
printf("%5d",i); fflush(stdout);
printf(" addr: %p", mem_item[i].addr); fflush(stdout);
printf(" size: %5d", mem_item[i].addr->size); fflush(stdout);
printf(" age: %6d", tick - mem_item[i].est); fflush(stdout);
printf(" file: %s", mem_item[i].filen); fflush(stdout);
printf(":%d", mem_item[i].line); fflush(stdout);
if (mem_item[i].blen != 0) {
printf(" \tblen %d", mem_item[i].blen);
fflush(stdout);
}
printf("\n");
}
printf("Program initialisation finished at age %6d\n", tick-init);
qsort(mem_item, naddr, sizeof(mem_item[0]), mem_key_cmp);
}
/* Because block_alloc recycles blocks we need to know which code
* fragment takes over responsibility for the memory. */
/**
* xclaim:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -