xref: /netbsd-src/external/gpl2/lvm2/dist/libdm/mm/dbg_malloc.c (revision 7c604eea85b4f330dc75ffe65e947f4d73758aa0)
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