/*
#ident	"@(#)smail/src:RELEASE-3_2_0_121:alloc.h,v 1.21 2005/07/20 20:34:56 woods Exp"
 */

/*
 *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
 *    Copyright (C) 1992  Ronald S. Karr
 * 
 * See the file COPYING, distributed with smail, for restriction
 * and warranty information.
 */

/*
 * alloc.h:
 *	block storage allocation
 * 	    This allows a given storage allocation to be associated 
 *	    with a group of other storage allocations.  It is
 *	    possible to free or test for existence of the class.
 *
 *	    A block a pointer to a chain of segments.  Each segment
 *	    refers to one storage allocation.  A block also contains
 *	    the total number of segments allocated.  If this number is
 *	    zero, then no storage is associated with the block.
 */

/*
 * block allocation data structure
 */
struct block {
    struct bseg *next;	/* if cnt > 0 then next holds segment chain */
    int cnt;		/* number of segments in the block */
};
struct bseg {
    struct bseg *next;	/* if != NULL, then next alloc in block */
    char *data;		/* the storage allocated */
};

/*
 * handy macros to determine if a block is active
 */
#define is_memory(block_ptr) ((struct block *)(block_ptr)->cnt)
#define is_free(block_ptr) (!(struct block *)(block_ptr)->cnt)

/*
 * X_CHECK - check for the xmalloc magic number
 *
 * As a debugging aid against double xfree(), as well as to protect against the
 * the use of freed storage, the integer X_MAGIC is stored at the beginning of
 * each block allocated with xmalloc().  This integer is then cleared after a
 * call to xfree() has marked the block as free.
 *
 * The macro X_CHECK() checks for the X_MAGIC value and calls panic() if it
 * does not exist and iff x_dont_panic is false.  This macro should be used
 * whenever a pointer value which might be freed and reallocated multiple times
 * is used (e.g. in the STR_*() macros).  xfree() itself checks that it doesn't
 * try to free storage thats already marked as free.
 *
 * In an ideal world we would put another, different, canary value at the
 * precise end of the requested storage, but that would require keeping track
 * of the requested size of each block, e.g. by storing it right next to the
 * magic number at the start of the block.  In a perfect world that second
 * canary value would be impossible for an attacker to predict (i.e. it might
 * be a random number that's obtained at startup), but of course in the real
 * world that number would be scattered all over at all kinds of predictable
 * locations so the attacker could probably find and copy it anyway.
 *
 * XXX if we knew the size of the ALIGNED_TYPE then we could provide more bits
 * of random data for this canary on machines where we have more room to store
 * them in.  Maybe we should at least try to force sign extension to fill out
 * the empty bits with ones so that they are more obvious from a debugger.
 *
 * XXX maybe the x_dont_panic flag should be promoted to be handled by panic()
 * so that this macro could just use panic() instead of having to use
 * write_log() and abort() directly.
 */
#define X_MAGIC		((ALIGNED_TYPE)0xe8f987b1)
#define X_CHECK_MESSAGE	"X_CHECK failed!  ptr=%p, line=%d, file=%s   Please trace under a debugger!"
#define X_CHECK(p)					\
	(((ALIGNED_TYPE *)(p))[-1] != X_MAGIC ?		\
		(write_log(WRITE_LOG_PANIC|WRITE_LOG_SYS|WRITE_LOG_TTY,\
			   X_CHECK_MESSAGE,		\
			   (POINTER_TYPE)(p),		\
			   __LINE__,			\
			   __FILE__),			\
		 x_dont_panic ?				\
		    FAIL :				\
		    (abort(), 0))			\
	    : SUCCEED)
 

/* use these macros to panic code which should not generate a panic */
#define X_NO_PANIC() (x_dont_panic = TRUE)
#define X_PANIC_OKAY() (x_dont_panic = FALSE)

/* XXX this should be an all-uppercase symbol to warn users of side-effects!!! */
#define xrealloc(ptr, sz)				\
	(X_CHECK(ptr) == SUCCEED ?			\
		priv_xrealloc(ptr, sz) :		\
		NULL)

#define XFREE_NULL_MESSAGE	"xfree(NULL) called at line=%d, file=%s   Please trace under a debugger!"
/* XXX this might best be an all-uppercase symbol to warn users of side-effects!!! */
/* XXX should this honour x_dont_panic!?!?!? */
#define xfree(ptr)					\
	((ptr == NULL) ? 				\
		(panic(EX_SOFTWARE,			\
		       XFREE_NULL_MESSAGE,		\
		      __LINE__, __FILE__),FAIL) :	\
	 	(X_CHECK(ptr) == SUCCEED ?		\
			(priv_xfree(ptr),SUCCEED) :	\
			FAIL))

#define X_IS_XALLOC(p)	(((ALIGNED_TYPE *)(p))[-1] == X_MAGIC)

/* external variables defined in alloc.c */
extern int x_dont_panic;		/* dont panic in X_CHECK() */

/* external functions defined in alloc.c */
extern char *xmalloc __P((size_t));
extern char *priv_xrealloc __P((char *, size_t));
extern void priv_xfree __P((char *));
extern char *bmalloc __P((size_t, struct block *));
extern char *brealloc __P((char *, size_t, struct block *));
extern void bfree __P((char *, struct block *));
extern struct block *malloc_block __P((void));
extern void realloc_block __P((char *, struct block *, struct block *));
extern void free_block __P((struct block *));

/* 
 * Local Variables:
 * c-file-style: "smail"
 * End:
 */
