get size of malloc'd object

Chris Torek chris at umcp-cs.UUCP
Thu Jun 19 05:12:43 AEST 1986


In article <2206 at peora.UUCP>, jer at peora.UUCP (J. Eric Roskos) writes:
>... allocate a sizeof(int) worth of extra space, then store the
>size of the thing you malloc'ed in the int at the front of the
>allocated block, advance the pointer past the place where your
>stored the size, and return that as the pointer to the block you
>allocated.
>
>This approach is portable, simple, and easy to understand.  Also
>it doesn't require any assumptions about what kind of objects are
>being allocated.

Unfortunately, it is not necessarily portable.  I can imagine a
machine where `double' arguments must be aligned on an eight-byte
boundary, but integers are only four bytes wide.  In this case
calling the new routine to allocate doubles would result in an
odd-address-style trap when the returned value is used.

What can be done is this:

	#include <stdio.h>

	/* change all `char *'s to `void *'s in ANSI C */
	struct mymem {
		struct	mymem *m_next;	/* linked list */
		struct	mymem *m_prev;	/* doubly, for easy removal */
		unsigned m_size;	/* size of mem, in bytes */
		char	*m_mem;		/* storage */
	};

	/* queue head */
	static struct mymem m_base = { &m_base, &m_base };

	extern char *malloc();

	/*
	 * Allocate some memory, remembering its size.
	 */
	char *
	myalloc(size)
		unsigned size;
	{
		register struct mymem *m;

		if ((m = (struct mymem *) malloc(sizeof (*m))) == NULL)
			return (NULL);
		if ((m->m_mem = malloc(size)) == NULL) {
			free((char *) m);
			return (NULL);
		}
		m->m_size = size;
		/*
		 * Insert at head: change to tail if mem usage is more
		 * `queueish' than `stackish'.
		 */
		m->m_next = m_base.m_next;
		m->m_prev = &m_base;
		m_base.m_next->m_prev = m;
		m_base.m_next = m;
		return (m->m_mem);
	}

	/*
	 * Locate the queue element corresponding to the given memory
	 * region.
	 */
	static struct mymem *
	myfind(mem)
		register char *mem;
	{
		register struct mymem *m = &m_base;

		while ((m = m->m_next) != &m_base)
			if (m->m_mem == mem)
				return (m);
		return (NULL);
	}

	/*
	 * Free a region, and drop it from the queue.
	 */
	myfree(mem)
		char *mem;
	{
		register struct mymem *m = myfind(mem);

		if (m == NULL) {
			/*
			 * Complain?  Abort?  Or what?
			 * Change to suit local tastes...
			 */
			(void) fprintf(stderr, "myfree: invalid free\n");
			(void) fflush(stderr);
			abort();
		}
		/* remove from queue */
		m->m_next->m_prev = m->m_prev;
		m->m_prev->m_next = m->m_next;
		/* and discard */
		free(m->m_mem);
		free((char *) m);
	}

	unsigned
	mysize(mem)
		char *mem;
	{
		struct mymem *m;

		if ((m = myfind(mem)) == NULL)
			return (0);	/* not allocated */
		return (m->m_size);
	}

This definitely *is* portable, if slow for large remembrance queues.

Of course, malloc() knows all along how big the allocated region
is (though the number it knows might be larger than the original
request); so it is a shame to have to go through all this effort.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris at umcp-cs		ARPA:	chris at mimsy.umd.edu



More information about the Comp.unix mailing list