1*7c604eeaShaad /* $NetBSD: dbg_malloc.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $ */
256a34939Shaad
356a34939Shaad /*
456a34939Shaad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
656a34939Shaad *
756a34939Shaad * This file is part of the device-mapper userspace tools.
856a34939Shaad *
956a34939Shaad * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad *
1356a34939Shaad * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1656a34939Shaad */
1756a34939Shaad
1856a34939Shaad #include "dmlib.h"
1956a34939Shaad
2056a34939Shaad #include <assert.h>
2156a34939Shaad #include <stdarg.h>
2256a34939Shaad
dm_strdup_aux(const char * str,const char * file,int line)2356a34939Shaad char *dm_strdup_aux(const char *str, const char *file, int line)
2456a34939Shaad {
2556a34939Shaad char *ret;
2656a34939Shaad
2756a34939Shaad if (!str) {
2856a34939Shaad log_error("Internal error: dm_strdup called with NULL pointer");
2956a34939Shaad return NULL;
3056a34939Shaad }
3156a34939Shaad
3256a34939Shaad if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
3356a34939Shaad strcpy(ret, str);
3456a34939Shaad
3556a34939Shaad return ret;
3656a34939Shaad }
3756a34939Shaad
3856a34939Shaad struct memblock {
3956a34939Shaad struct memblock *prev, *next; /* All allocated blocks are linked */
4056a34939Shaad size_t length; /* Size of the requested block */
4156a34939Shaad int id; /* Index of the block */
4256a34939Shaad const char *file; /* File that allocated */
4356a34939Shaad int line; /* Line that allocated */
4456a34939Shaad void *magic; /* Address of this block */
4556a34939Shaad } __attribute__((aligned(8)));
4656a34939Shaad
4756a34939Shaad static struct {
4856a34939Shaad unsigned block_serialno;/* Non-decreasing serialno of block */
4956a34939Shaad unsigned blocks_allocated; /* Current number of blocks allocated */
5056a34939Shaad unsigned blocks_max; /* Max no of concurrently-allocated blocks */
5156a34939Shaad unsigned int bytes, mbytes;
5256a34939Shaad
5356a34939Shaad } _mem_stats = {
5456a34939Shaad 0, 0, 0, 0, 0};
5556a34939Shaad
5656a34939Shaad static struct memblock *_head = 0;
5756a34939Shaad static struct memblock *_tail = 0;
5856a34939Shaad
dm_malloc_aux_debug(size_t s,const char * file,int line)5956a34939Shaad void *dm_malloc_aux_debug(size_t s, const char *file, int line)
6056a34939Shaad {
6156a34939Shaad struct memblock *nb;
6256a34939Shaad size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
6356a34939Shaad
6456a34939Shaad if (s > 50000000) {
6556a34939Shaad log_error("Huge memory allocation (size %" PRIsize_t
6656a34939Shaad ") rejected - metadata corruption?", s);
6756a34939Shaad return 0;
6856a34939Shaad }
6956a34939Shaad
7056a34939Shaad if (!(nb = malloc(tsize))) {
7156a34939Shaad log_error("couldn't allocate any memory, size = %" PRIsize_t,
7256a34939Shaad s);
7356a34939Shaad return 0;
7456a34939Shaad }
7556a34939Shaad
7656a34939Shaad /* set up the file and line info */
7756a34939Shaad nb->file = file;
7856a34939Shaad nb->line = line;
7956a34939Shaad
8056a34939Shaad dm_bounds_check();
8156a34939Shaad
8256a34939Shaad /* setup fields */
8356a34939Shaad nb->magic = nb + 1;
8456a34939Shaad nb->length = s;
8556a34939Shaad nb->id = ++_mem_stats.block_serialno;
8656a34939Shaad nb->next = 0;
8756a34939Shaad
8856a34939Shaad /* stomp a pretty pattern across the new memory
8956a34939Shaad and fill in the boundary bytes */
9056a34939Shaad {
9156a34939Shaad char *ptr = (char *) (nb + 1);
9256a34939Shaad size_t i;
9356a34939Shaad for (i = 0; i < s; i++)
9456a34939Shaad *ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe;
9556a34939Shaad
9656a34939Shaad for (i = 0; i < sizeof(unsigned long); i++)
9756a34939Shaad *ptr++ = (char) nb->id;
9856a34939Shaad }
9956a34939Shaad
10056a34939Shaad nb->prev = _tail;
10156a34939Shaad
10256a34939Shaad /* link to tail of the list */
10356a34939Shaad if (!_head)
10456a34939Shaad _head = _tail = nb;
10556a34939Shaad else {
10656a34939Shaad _tail->next = nb;
10756a34939Shaad _tail = nb;
10856a34939Shaad }
10956a34939Shaad
11056a34939Shaad _mem_stats.blocks_allocated++;
11156a34939Shaad if (_mem_stats.blocks_allocated > _mem_stats.blocks_max)
11256a34939Shaad _mem_stats.blocks_max = _mem_stats.blocks_allocated;
11356a34939Shaad
11456a34939Shaad _mem_stats.bytes += s;
11556a34939Shaad if (_mem_stats.bytes > _mem_stats.mbytes)
11656a34939Shaad _mem_stats.mbytes = _mem_stats.bytes;
11756a34939Shaad
11856a34939Shaad /* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
11956a34939Shaad _mem_stats.bytes); */
12056a34939Shaad
12156a34939Shaad return nb + 1;
12256a34939Shaad }
12356a34939Shaad
dm_free_aux(void * p)12456a34939Shaad void dm_free_aux(void *p)
12556a34939Shaad {
12656a34939Shaad char *ptr;
12756a34939Shaad size_t i;
12856a34939Shaad struct memblock *mb = ((struct memblock *) p) - 1;
12956a34939Shaad if (!p)
13056a34939Shaad return;
13156a34939Shaad
13256a34939Shaad dm_bounds_check();
13356a34939Shaad
13456a34939Shaad /* sanity check */
13556a34939Shaad assert(mb->magic == p);
13656a34939Shaad
13756a34939Shaad /* check data at the far boundary */
13856a34939Shaad ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
13956a34939Shaad for (i = 0; i < sizeof(unsigned long); i++)
14056a34939Shaad if (*ptr++ != (char) mb->id)
14156a34939Shaad assert(!"Damage at far end of block");
14256a34939Shaad
14356a34939Shaad /* have we freed this before ? */
14456a34939Shaad assert(mb->id != 0);
14556a34939Shaad
14656a34939Shaad /* unlink */
14756a34939Shaad if (mb->prev)
14856a34939Shaad mb->prev->next = mb->next;
14956a34939Shaad else
15056a34939Shaad _head = mb->next;
15156a34939Shaad
15256a34939Shaad if (mb->next)
15356a34939Shaad mb->next->prev = mb->prev;
15456a34939Shaad else
15556a34939Shaad _tail = mb->prev;
15656a34939Shaad
15756a34939Shaad mb->id = 0;
15856a34939Shaad
15956a34939Shaad /* stomp a different pattern across the memory */
16056a34939Shaad ptr = ((char *) mb) + sizeof(struct memblock);
16156a34939Shaad for (i = 0; i < mb->length; i++)
16256a34939Shaad *ptr++ = i & 1 ? (char) 0xde : (char) 0xad;
16356a34939Shaad
16456a34939Shaad assert(_mem_stats.blocks_allocated);
16556a34939Shaad _mem_stats.blocks_allocated--;
16656a34939Shaad _mem_stats.bytes -= mb->length;
16756a34939Shaad
16856a34939Shaad /* free the memory */
16956a34939Shaad free(mb);
17056a34939Shaad }
17156a34939Shaad
dm_realloc_aux(void * p,unsigned int s,const char * file,int line)17256a34939Shaad void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
17356a34939Shaad {
17456a34939Shaad void *r;
17556a34939Shaad struct memblock *mb = ((struct memblock *) p) - 1;
17656a34939Shaad
17756a34939Shaad r = dm_malloc_aux_debug(s, file, line);
17856a34939Shaad
17956a34939Shaad if (p) {
18056a34939Shaad memcpy(r, p, mb->length);
18156a34939Shaad dm_free_aux(p);
18256a34939Shaad }
18356a34939Shaad
18456a34939Shaad return r;
18556a34939Shaad }
18656a34939Shaad
dm_dump_memory_debug(void)18756a34939Shaad int dm_dump_memory_debug(void)
18856a34939Shaad {
18956a34939Shaad unsigned long tot = 0;
19056a34939Shaad struct memblock *mb;
19156a34939Shaad char str[32];
19256a34939Shaad size_t c;
19356a34939Shaad
19456a34939Shaad if (_head)
19556a34939Shaad log_very_verbose("You have a memory leak:");
19656a34939Shaad
19756a34939Shaad for (mb = _head; mb; mb = mb->next) {
19856a34939Shaad for (c = 0; c < sizeof(str) - 1; c++) {
19956a34939Shaad if (c >= mb->length)
20056a34939Shaad str[c] = ' ';
20156a34939Shaad else if (*(char *)(mb->magic + c) == '\0')
20256a34939Shaad str[c] = '\0';
20356a34939Shaad else if (*(char *)(mb->magic + c) < ' ')
20456a34939Shaad str[c] = '?';
20556a34939Shaad else
20656a34939Shaad str[c] = *(char *)(mb->magic + c);
20756a34939Shaad }
20856a34939Shaad str[sizeof(str) - 1] = '\0';
20956a34939Shaad
210*7c604eeaShaad LOG_MESG(_LOG_INFO, mb->file, mb->line, 0,
21156a34939Shaad "block %d at %p, size %" PRIsize_t "\t [%s]",
21256a34939Shaad mb->id, mb->magic, mb->length, str);
21356a34939Shaad tot += mb->length;
21456a34939Shaad }
21556a34939Shaad
21656a34939Shaad if (_head)
21756a34939Shaad log_very_verbose("%ld bytes leaked in total", tot);
21856a34939Shaad
21956a34939Shaad return 1;
22056a34939Shaad }
22156a34939Shaad
dm_bounds_check_debug(void)22256a34939Shaad void dm_bounds_check_debug(void)
22356a34939Shaad {
22456a34939Shaad struct memblock *mb = _head;
22556a34939Shaad while (mb) {
22656a34939Shaad size_t i;
22756a34939Shaad char *ptr = ((char *) (mb + 1)) + mb->length;
22856a34939Shaad for (i = 0; i < sizeof(unsigned long); i++)
22956a34939Shaad if (*ptr++ != (char) mb->id)
23056a34939Shaad assert(!"Memory smash");
23156a34939Shaad
23256a34939Shaad mb = mb->next;
23356a34939Shaad }
23456a34939Shaad }
23556a34939Shaad
dm_malloc_aux(size_t s,const char * file __attribute ((unused)),int line __attribute ((unused)))23656a34939Shaad void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
23756a34939Shaad int line __attribute((unused)))
23856a34939Shaad {
23956a34939Shaad if (s > 50000000) {
24056a34939Shaad log_error("Huge memory allocation (size %" PRIsize_t
24156a34939Shaad ") rejected - metadata corruption?", s);
24256a34939Shaad return 0;
24356a34939Shaad }
24456a34939Shaad
24556a34939Shaad return malloc(s);
24656a34939Shaad }
247