freebsd-dev/usr.bin/grep/regex/xmalloc.c
Ed Schouten bf70becee6 More -Wmissing-variable-declarations fixes.
In addition to adding `static' where possible:

- bin/date: Move `retval' into extern.h to make it visible to date.c.
- bin/ed: Move globally used variables into ed.h.
- sbin/camcontrol: Move `verbose' into camcontrol.h and fix shadow warnings.
- usr.bin/calendar: Remove unneeded variables.
- usr.bin/chat: Make `line' local instead of global.
- usr.bin/elfdump: Comment out unneeded function.
- usr.bin/rlogin: Use _Noreturn instead of __dead2.
- usr.bin/tset: Pull `Ospeed' into extern.h.
- usr.sbin/mfiutil: Put global variables in mfiutil.h.
- usr.sbin/pkg: Remove unused `os_corres'.
- usr.sbin/quotaon, usr.sbin/repquota: Remove unused `qfname'.
2012-10-19 14:49:42 +00:00

350 lines
6.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* $FreeBSD$ */
/*
xmalloc.c - Simple malloc debugging library implementation
This software is released under a BSD-style license.
See the file LICENSE for details and copyright.
*/
/*
TODO:
- red zones
- group dumps by source location
*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#define XMALLOC_INTERNAL 1
#include "xmalloc.h"
/*
Internal stuff.
*/
typedef struct hashTableItemRec {
void *ptr;
int bytes;
const char *file;
int line;
const char *func;
struct hashTableItemRec *next;
} hashTableItem;
typedef struct {
hashTableItem **table;
} hashTable;
static int xmalloc_peak;
static int xmalloc_current;
static int xmalloc_peak_blocks;
static int xmalloc_current_blocks;
static int xmalloc_fail_after;
#define TABLE_BITS 8
#define TABLE_MASK ((1 << TABLE_BITS) - 1)
#define TABLE_SIZE (1 << TABLE_BITS)
static hashTable *
hash_table_new(void)
{
hashTable *tbl;
tbl = malloc(sizeof(*tbl));
if (tbl != NULL)
{
tbl->table = calloc(TABLE_SIZE, sizeof(*tbl->table));
if (tbl->table == NULL)
{
free(tbl);
return NULL;
}
}
return tbl;
}
static int
hash_void_ptr(void *ptr)
{
int hash;
int i;
/* I took this hash function just off the top of my head, I have
no idea whether it is bad or very bad. */
hash = 0;
for (i = 0; i < (int)sizeof(ptr)*8 / TABLE_BITS; i++)
{
hash ^= (unsigned long)ptr >> i*8;
hash += i * 17;
hash &= TABLE_MASK;
}
return hash;
}
static void
hash_table_add(hashTable *tbl, void *ptr, int bytes,
const char *file, int line, const char *func)
{
int i;
hashTableItem *item, *new;
i = hash_void_ptr(ptr);
item = tbl->table[i];
if (item != NULL)
while (item->next != NULL)
item = item->next;
new = malloc(sizeof(*new));
assert(new != NULL);
new->ptr = ptr;
new->bytes = bytes;
new->file = file;
new->line = line;
new->func = func;
new->next = NULL;
if (item != NULL)
item->next = new;
else
tbl->table[i] = new;
xmalloc_current += bytes;
if (xmalloc_current > xmalloc_peak)
xmalloc_peak = xmalloc_current;
xmalloc_current_blocks++;
if (xmalloc_current_blocks > xmalloc_peak_blocks)
xmalloc_peak_blocks = xmalloc_current_blocks;
}
static void
hash_table_del(hashTable *tbl, void *ptr)
{
int i;
hashTableItem *item, *prev;
i = hash_void_ptr(ptr);
item = tbl->table[i];
if (item == NULL)
{
printf("xfree: invalid ptr %p\n", ptr);
abort();
}
prev = NULL;
while (item->ptr != ptr)
{
prev = item;
item = item->next;
}
if (item->ptr != ptr)
{
printf("xfree: invalid ptr %p\n", ptr);
abort();
}
xmalloc_current -= item->bytes;
xmalloc_current_blocks--;
if (prev != NULL)
{
prev->next = item->next;
free(item);
}
else
{
tbl->table[i] = item->next;
free(item);
}
}
static hashTable *xmalloc_table = NULL;
static void
xmalloc_init(void)
{
if (xmalloc_table == NULL)
{
xmalloc_table = hash_table_new();
xmalloc_peak = 0;
xmalloc_peak_blocks = 0;
xmalloc_current = 0;
xmalloc_current_blocks = 0;
xmalloc_fail_after = -1;
}
assert(xmalloc_table != NULL);
assert(xmalloc_table->table != NULL);
}
/*
Public API.
*/
void
xmalloc_configure(int fail_after)
{
xmalloc_init();
xmalloc_fail_after = fail_after;
}
int
xmalloc_dump_leaks(void)
{
int i;
int num_leaks = 0;
int leaked_bytes = 0;
hashTableItem *item;
xmalloc_init();
for (i = 0; i < TABLE_SIZE; i++)
{
item = xmalloc_table->table[i];
while (item != NULL)
{
printf("%s:%d: %s: %d bytes at %p not freed\n",
item->file, item->line, item->func, item->bytes, item->ptr);
num_leaks++;
leaked_bytes += item->bytes;
item = item->next;
}
}
if (num_leaks == 0)
printf("No memory leaks.\n");
else
printf("%d unfreed memory chuncks, total %d unfreed bytes.\n",
num_leaks, leaked_bytes);
printf("Peak memory consumption %d bytes (%.1f kB, %.1f MB) in %d blocks ",
xmalloc_peak, (double)xmalloc_peak / 1024,
(double)xmalloc_peak / (1024*1024), xmalloc_peak_blocks);
printf("(average ");
if (xmalloc_peak_blocks)
printf("%d", ((xmalloc_peak + xmalloc_peak_blocks / 2)
/ xmalloc_peak_blocks));
else
printf("N/A");
printf(" bytes per block).\n");
return num_leaks;
}
void *
xmalloc_impl(size_t size, const char *file, int line, const char *func)
{
void *ptr;
xmalloc_init();
assert(size > 0);
if (xmalloc_fail_after == 0)
{
xmalloc_fail_after = -2;
#if 0
printf("xmalloc: forced failure %s:%d: %s\n", file, line, func);
#endif
return NULL;
}
else if (xmalloc_fail_after == -2)
{
printf("xmalloc: called after failure from %s:%d: %s\n",
file, line, func);
assert(0);
}
else if (xmalloc_fail_after > 0)
xmalloc_fail_after--;
ptr = malloc(size);
if (ptr != NULL)
hash_table_add(xmalloc_table, ptr, (int)size, file, line, func);
return ptr;
}
void *
xcalloc_impl(size_t nmemb, size_t size, const char *file, int line,
const char *func)
{
void *ptr;
xmalloc_init();
assert(size > 0);
if (xmalloc_fail_after == 0)
{
xmalloc_fail_after = -2;
#if 0
printf("xcalloc: forced failure %s:%d: %s\n", file, line, func);
#endif
return NULL;
}
else if (xmalloc_fail_after == -2)
{
printf("xcalloc: called after failure from %s:%d: %s\n",
file, line, func);
assert(0);
}
else if (xmalloc_fail_after > 0)
xmalloc_fail_after--;
ptr = calloc(nmemb, size);
if (ptr != NULL)
hash_table_add(xmalloc_table, ptr, (int)(nmemb * size), file, line, func);
return ptr;
}
void
xfree_impl(void *ptr, const char *file, int line, const char *func)
{
/*LINTED*/(void)&file;
/*LINTED*/(void)&line;
/*LINTED*/(void)&func;
xmalloc_init();
if (ptr != NULL)
hash_table_del(xmalloc_table, ptr);
free(ptr);
}
void *
xrealloc_impl(void *ptr, size_t new_size, const char *file, int line,
const char *func)
{
void *new_ptr;
xmalloc_init();
assert(ptr != NULL);
assert(new_size > 0);
if (xmalloc_fail_after == 0)
{
xmalloc_fail_after = -2;
return NULL;
}
else if (xmalloc_fail_after == -2)
{
printf("xrealloc: called after failure from %s:%d: %s\n",
file, line, func);
assert(0);
}
else if (xmalloc_fail_after > 0)
xmalloc_fail_after--;
new_ptr = realloc(ptr, new_size);
if (new_ptr != NULL)
{
hash_table_del(xmalloc_table, ptr);
hash_table_add(xmalloc_table, new_ptr, (int)new_size, file, line, func);
}
return new_ptr;
}
/* EOF */