rewrite the cookie logic… while this is better than previously,

we still have issues:

(gdb) r
Starting program: /usr/obj/bin/mksh/mksh -c print\ \$KSH_VERSION
mksh in free(): error: modified (chunk-) pointer

Program received signal SIGABRT, Aborted.
This commit is contained in:
tg 2008-11-15 11:42:18 +00:00
parent 1ca9790f1d
commit 90e8e7ea72
2 changed files with 188 additions and 138 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/Makefile,v 1.68 2008/11/12 07:38:42 tg Exp $ # $MirOS: src/bin/mksh/Makefile,v 1.69 2008/11/15 11:42:18 tg Exp $
#- #-
# use CPPFLAGS=-DDEBUG __CRAZY=Yes to check for certain more stuff # use CPPFLAGS=-DDEBUG __CRAZY=Yes to check for certain more stuff
@ -10,7 +10,7 @@ SRCS= aalloc.c edit.c eval.c exec.c expr.c funcs.c histrap.c \
.if !make(test-build) .if !make(test-build)
. if ${DEBUGLIBS:L} == "yes" . if ${DEBUGLIBS:L} == "yes"
CPPFLAGS+= -DMKSH_AFREE_DEBUG # MirOS development version CPPFLAGS+= -DMKSH_AFREE_DEBUG # MirOS development version
CPPFLAGS+= -DAALLOC_TRACK # MirOS development version #CPPFLAGS+= -DAALLOC_TRACK # MirOS development version
. endif . endif
CPPFLAGS+= -DAALLOC_NO_COOKIES # for now… aalloc cookies are broken CPPFLAGS+= -DAALLOC_NO_COOKIES # for now… aalloc cookies are broken
CPPFLAGS+= -DMKSH_ASSUME_UTF8 \ CPPFLAGS+= -DMKSH_ASSUME_UTF8 \

314
aalloc.c
View File

@ -1,6 +1,6 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/aalloc.c,v 1.30 2008/11/15 09:05:29 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/aalloc.c,v 1.31 2008/11/15 11:42:18 tg Exp $");
/* mksh integration of aalloc */ /* mksh integration of aalloc */
@ -66,24 +66,45 @@ aalloc_warn(const char *fmt, ...)
#undef AALLOC_DEBUG #undef AALLOC_DEBUG
#undef AALLOC_STATS #undef AALLOC_STATS
#undef AALLOC_TRACK #undef AALLOC_TRACK
#ifndef AALLOC_NO_COOKIES
#define AALLOC_NO_COOKIES
#endif
#elif defined(AALLOC_STATS) && !defined(AALLOC_TRACK) #elif defined(AALLOC_STATS) && !defined(AALLOC_TRACK)
#define AALLOC_TRACK #define AALLOC_TRACK
#endif #endif
#define PVALIGN (sizeof (void *)) #define PVALIGN (sizeof (void *))
#define PVMASK (sizeof (void *) - 1) #define PVMASK (sizeof (void *) - 1)
#define isunaligned(p) (((ptrdiff_t)(p) & PVMASK) != 0)
#ifndef AALLOC_INITSZ #ifndef AALLOC_INITSZ
#define AALLOC_INITSZ (64 * PVALIGN) /* at least 4 pointers */ #define AALLOC_INITSZ (64 * PVALIGN) /* at least 4 pointers */
#endif #endif
typedef /* unsigned */ ptrdiff_t TCookie; typedef /* unsigned */ ptrdiff_t TCookie;
typedef union {
/* unsigned */ ptrdiff_t xv;
} TCooked;
typedef union { typedef union {
TCookie iv; ptrdiff_t nv;
char *pv; char *cp;
} TPtr; } TPtr;
#ifdef AALLOC_NO_COOKIES
#define ldcook(p, cv, c) ((p).nv = (cv).xv, (p).nv)
#define stcook(cv, p, c) ((cv).xv = (p).nv, (p).nv)
#define stcookp(cv, p, c) (xp.cp = (char *)(p), (cv).xv = xp.nv, xp.nv)
#define stcooki(cv, i, c) ((cv).xv = (xp.nv = (i)), xp.nv)
#define iscook(c) true
#else
#define ldcook(p, cv, c) ((p).nv = (cv).xv ^ (c), (p).nv)
#define stcook(cv, p, c) ((cv).xv = (p).nv ^ (c), (p).nv)
#define stcookp(cv, p, c) (xp.cp = (char *)(p), (cv).xv = xp.nv ^ (c), xp.nv)
#define stcooki(cv, i, c) ((cv).xv = (xp.nv = (i)) ^ (c), xp.nv)
#define iscook(c) isunaligned(c)
#endif
/* /*
* The separation between TBlock and TArea does not seem to make * The separation between TBlock and TArea does not seem to make
* sense at first, especially in the !AALLOC_TRACK case, but is * sense at first, especially in the !AALLOC_TRACK case, but is
@ -97,7 +118,9 @@ typedef union {
*/ */
struct TBlock { struct TBlock {
TCookie cookie; #ifndef AALLOC_NO_COOKIES
TCookie bcookie;
#endif
char *endp; char *endp;
char *last; char *last;
void *storage; void *storage;
@ -105,10 +128,12 @@ struct TBlock {
typedef struct TBlock *PBlock; typedef struct TBlock *PBlock;
struct TArea { struct TArea {
TPtr bp; TCooked bp;
#ifdef AALLOC_TRACK #ifdef AALLOC_TRACK
TPtr prev; TCooked prev;
TCookie ocookie; #ifndef AALLOC_NO_COOKIES
TCookie scookie;
#endif
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
const char *name; const char *name;
unsigned long numalloc; unsigned long numalloc;
@ -118,12 +143,7 @@ struct TArea {
#endif #endif
}; };
static TCookie global_cookie; static TCookie fcookie;
#ifdef AALLOC_NO_COOKIES
#define gcookie 0
#else
#define gcookie global_cookie
#endif
#ifdef AALLOC_TRACK #ifdef AALLOC_TRACK
static PArea track; static PArea track;
@ -164,7 +184,7 @@ static long pagesz;
if ((dest) == NULL) \ if ((dest) == NULL) \
AALLOC_ABORT("unable to allocate %lu bytes: %s", \ AALLOC_ABORT("unable to allocate %lu bytes: %s", \
(unsigned long)(len), strerror(errno)); \ (unsigned long)(len), strerror(errno)); \
if ((ptrdiff_t)(dest) & PVMASK) \ if (isunaligned(dest)) \
AALLOC_ABORT("unaligned malloc result: %p", (dest)); \ AALLOC_ABORT("unaligned malloc result: %p", (dest)); \
} while (/* CONSTCOND */ 0) } while (/* CONSTCOND */ 0)
@ -183,7 +203,8 @@ static long pagesz;
static void adelete_leak(PArea, PBlock, bool, const char *); static void adelete_leak(PArea, PBlock, bool, const char *);
static PBlock check_bp(PArea, const char *, TCookie); static PBlock check_bp(PArea, const char *, TCookie);
static TPtr *check_ptr(void *, PArea, PBlock *, const char *, const char *); static TCooked *check_ptr(void *, PArea, PBlock *, TPtr *, const char *,
const char *);
PArea PArea
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
@ -194,6 +215,7 @@ anew(size_t hint)
{ {
PArea ap; PArea ap;
PBlock bp; PBlock bp;
TPtr xp;
AALLOC_THREAD_ENTER(NULL) AALLOC_THREAD_ENTER(NULL)
@ -210,10 +232,12 @@ anew(size_t hint)
if (PVALIGN != 2 && PVALIGN != 4 && PVALIGN != 8 && PVALIGN != 16) if (PVALIGN != 2 && PVALIGN != 4 && PVALIGN != 8 && PVALIGN != 16)
AALLOC_ABORT("PVALIGN not a power of two: %lu", AALLOC_ABORT("PVALIGN not a power of two: %lu",
(unsigned long)PVALIGN); (unsigned long)PVALIGN);
if (sizeof (TPtr) != sizeof (TCookie) || sizeof (TPtr) != PVALIGN) if (sizeof (TPtr) != sizeof (TCookie) || sizeof (TPtr) != PVALIGN ||
AALLOC_ABORT("TPtr sizes do not match: %lu, %lu, %lu", sizeof (TPtr) != sizeof (TCooked))
AALLOC_ABORT("TPtr sizes do not match: %lu, %lu, %lu, %lu",
(unsigned long)sizeof (TPtr), (unsigned long)sizeof (TPtr),
(unsigned long)sizeof (TCookie), (unsigned long)PVALIGN); (unsigned long)sizeof (TCookie), (unsigned long)PVALIGN,
(unsigned long)sizeof (TCooked));
if ((size_t)AALLOC_INITSZ < sizeof (struct TBlock)) if ((size_t)AALLOC_INITSZ < sizeof (struct TBlock))
AALLOC_ABORT("AALLOC_INITSZ constant too small: %lu < %lu", AALLOC_ABORT("AALLOC_INITSZ constant too small: %lu < %lu",
(unsigned long)AALLOC_INITSZ, (unsigned long)AALLOC_INITSZ,
@ -223,17 +247,22 @@ anew(size_t hint)
(unsigned long)hint); (unsigned long)hint);
#endif #endif
if (!global_cookie) { if (!fcookie) {
size_t v; #ifdef AALLOC_NO_COOKIES
fcookie++;
#else
size_t v = 0;
/* ensure unaligned cookie */ /* ensure unaligned cookie */
do { do {
global_cookie = AALLOC_RANDOM(); fcookie = AALLOC_RANDOM();
if (AALLOC_RANDOM() & 1)
v = AALLOC_RANDOM() & 7; v = AALLOC_RANDOM() & 7;
} while (!(global_cookie & PVMASK) || !v); } while (!iscook(fcookie) || !v);
/* randomise seed afterwards */ /* randomise seed afterwards */
while (v--) while (v--)
AALLOC_RANDOM(); AALLOC_RANDOM();
#endif
#ifdef AALLOC_TRACK #ifdef AALLOC_TRACK
atexit(track_check); atexit(track_check);
#endif #endif
@ -246,25 +275,23 @@ anew(size_t hint)
safe_malloc(ap, sizeof (struct TArea)); safe_malloc(ap, sizeof (struct TArea));
safe_malloc(bp, hint); safe_malloc(bp, hint);
/* ensure unaligned cookie */ /* ensure unaligned cookie */
#ifdef AALLOC_NO_COOKIES #ifndef AALLOC_NO_COOKIES
bp->cookie = 0;
#else
do { do {
bp->cookie = AALLOC_RANDOM(); bp->bcookie = AALLOC_RANDOM();
} while (!(bp->cookie & PVMASK)); } while (!iscook(bp->bcookie));
#endif #endif
/* first byte after block */ /* first byte after block */
bp->endp = (char *)bp + AALLOC_INITSZ; /* bp + size of the block */ bp->endp = (char *)bp + hint; /* bp + size of the block */
/* next entry (forward pointer) available for new allocation */ /* next entry (forward pointer) available for new allocation */
bp->last = (char *)&bp->storage; /* first entry */ bp->last = (char *)&bp->storage; /* first entry */
ap->bp.pv = (char *)bp; (void)stcookp(ap->bp, bp, fcookie);
ap->bp.iv ^= gcookie;
#ifdef AALLOC_TRACK #ifdef AALLOC_TRACK
ap->prev.pv = (char *)track; (void)stcookp(ap->prev, track, fcookie);
ap->prev.iv ^= gcookie; #ifndef AALLOC_NO_COOKIES
ap->ocookie = bp->cookie ^ gcookie; (void)stcooki(ap->scookie, bp->bcookie, fcookie);
#endif
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
ap->name = friendly_name ? friendly_name : "(no name)"; ap->name = friendly_name ? friendly_name : "(no name)";
ap->numalloc = 0; ap->numalloc = 0;
@ -283,12 +310,14 @@ anew(size_t hint)
* If ocookie is not 0, make sure block cookie is equal. * If ocookie is not 0, make sure block cookie is equal.
*/ */
static PBlock static PBlock
check_bp(PArea ap, const char *funcname, TCookie ocookie) check_bp(PArea ap, const char *funcname, TCookie ocookie __unused)
{ {
TPtr p; TPtr p;
PBlock bp; PBlock bp;
if (ap->bp.pv == NULL (void)ldcook(p, ap->bp, fcookie);
#ifndef AALLOC_SMALL
if (!p.nv
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
|| ap->isfree || ap->isfree
#endif #endif
@ -296,19 +325,23 @@ check_bp(PArea ap, const char *funcname, TCookie ocookie)
AALLOC_WARN("%s: area %p already freed", funcname, ap); AALLOC_WARN("%s: area %p already freed", funcname, ap);
return (NULL); return (NULL);
} }
p.iv = ap->bp.iv ^ gcookie; if (isunaligned(p.nv)) {
if ((ptrdiff_t)(bp = (PBlock)p.pv) & PVMASK) {
AALLOC_WARN("%s: area %p block pointer destroyed: %p", AALLOC_WARN("%s: area %p block pointer destroyed: %p",
funcname, ap, p.pv); funcname, ap, p.cp);
return (NULL); return (NULL);
} }
#endif
bp = (PBlock)p.cp;
AALLOC_PEEK(bp); AALLOC_PEEK(bp);
#ifndef AALLOC_NO_COOKIES
if (ocookie && bp->cookie != ocookie) { if (ocookie && bp->cookie != ocookie) {
AALLOC_WARN("%s: block %p cookie destroyed: %p, %p", AALLOC_WARN("%s: block %p cookie destroyed: %p, %p",
funcname, bp, (void *)ocookie, (void *)bp->cookie); funcname, bp, (void *)ocookie, (void *)bp->cookie);
return (NULL); return (NULL);
} }
if (((ptrdiff_t)bp->endp & PVMASK) || ((ptrdiff_t)bp->last & PVMASK)) { #endif
#ifndef AALLOC_SMALL
if (isunaligned(bp->endp) || isunaligned(bp->last)) {
AALLOC_WARN("%s: block %p data structure destroyed: %p, %p", AALLOC_WARN("%s: block %p data structure destroyed: %p, %p",
funcname, bp, bp->endp, bp->last); funcname, bp, bp->endp, bp->last);
return (NULL); return (NULL);
@ -324,6 +357,7 @@ check_bp(PArea ap, const char *funcname, TCookie ocookie)
bp->endp); bp->endp);
return (NULL); return (NULL);
} }
#endif
AALLOC_ALLOW(bp); AALLOC_ALLOW(bp);
return (bp); return (bp);
} }
@ -336,34 +370,32 @@ static void
track_check(void) track_check(void)
{ {
PArea tp; PArea tp;
TPtr lp;
PBlock bp; PBlock bp;
TCookie xc = 0;
TPtr xp;
AALLOC_THREAD_ENTER(NULL) AALLOC_THREAD_ENTER(NULL)
while (track) {
tp = track; tp = track;
while (tp) {
#ifndef AALLOC_NO_COOKIES
xc = ldcook(xp, tp->scookie, fcookie);
#endif
(void)ldcook(xp, tp->prev, fcookie);
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
AALLOC_WARN("AALLOC_STATS for %s(%p): %lu allocated, %lu at " AALLOC_WARN("AALLOC_STATS for %s(%p): %lu allocated, %lu at "
"once, %sfree", tp->name, tp, tp->numalloc, tp->maxalloc, "once, %sfree", tp->name, tp, tp->numalloc, tp->maxalloc,
tp->isfree ? "" : "not "); tp->isfree ? "" : "not ");
if (tp->isfree) if (tp->isfree)
goto track_next; goto track_check_next;
#endif #endif
tp->ocookie ^= gcookie; if (isunaligned(xp.nv) || !iscook(xc)) {
lp.iv = tp->prev.iv ^ gcookie;
if ((lp.iv & PVMASK)
#ifndef AALLOC_NO_COOKIES
|| !(tp->ocookie & PVMASK)
#endif
) {
/* buffer overflow or something? */ /* buffer overflow or something? */
AALLOC_WARN("AALLOC_TRACK data structure %p destroyed:" AALLOC_WARN("AALLOC_TRACK data structure %p destroyed:"
" %p, %p, %p; exiting", tp, lp.pv, tp->bp.pv, " %p, %p; exiting", tp, xp.cp, (void *)xc);
(void *)tp->ocookie);
break; break;
} }
if (!(bp = check_bp(tp, "atexit:track_check", tp->ocookie))) if (!(bp = check_bp(tp, "atexit:track_check", xc)))
goto track_next; goto track_check_next;
if (bp->last != (char *)&bp->storage) if (bp->last != (char *)&bp->storage)
#ifdef AALLOC_LEAK_SILENT #ifdef AALLOC_LEAK_SILENT
adelete_leak(tp, bp, false, "at exit"); adelete_leak(tp, bp, false, "at exit");
@ -374,9 +406,9 @@ track_check(void)
bp, (unsigned long)(bp->endp - (char *)bp)); bp, (unsigned long)(bp->endp - (char *)bp));
#endif #endif
free(bp); free(bp);
track_next: track_check_next:
track = (PArea)lp.pv;
free(tp); free(tp);
tp = (PArea)xp.cp;
} }
track = NULL; track = NULL;
AALLOC_THREAD_LEAVE(NULL) AALLOC_THREAD_LEAVE(NULL)
@ -386,29 +418,31 @@ track_check(void)
static void static void
adelete_leak(PArea ap, PBlock bp, bool always_warn, const char *when) adelete_leak(PArea ap, PBlock bp, bool always_warn, const char *when)
{ {
TPtr *cp; TPtr xp;
while (bp->last > (char *)&bp->storage) { while (bp->last > (char *)&bp->storage) {
bp->last -= PVALIGN; bp->last -= PVALIGN;
cp = *((void **)bp->last); (void)ldcook(xp, **((TCooked **)bp->last), bp->bcookie);
cp->iv ^= bp->cookie; #ifndef AALLOC_SMALL
if (always_warn || cp->pv != bp->last) if (always_warn || xp.cp != bp->last)
AALLOC_WARN("leaking %s pointer %p in area %p (%p %lu) %s", AALLOC_WARN("leaking %s pointer %p in area %p (ofs %p "
cp->pv == bp->last ? "valid" : "underflown", "len %lu) %s", xp.cp != bp->last ? "underflown" :
(char *)cp + PVALIGN, ap, bp, "valid", *((char **)bp->last) + PVALIGN, ap, bp,
(unsigned long)(bp->endp - (char *)bp), when); (unsigned long)(bp->endp - (char *)bp), when);
free(cp); #endif
free(xp.cp);
} }
} }
void void
adelete(PArea *pap) adelete(PArea *pap)
{ {
#ifdef AALLOC_TRACK
PArea tp;
TPtr lp;
#endif
PBlock bp; PBlock bp;
#if defined(AALLOC_TRACK) && !defined(AALLOC_STATS)
PArea tp;
TCookie xc = 0;
TPtr xp;
#endif
AALLOC_THREAD_ENTER(*pap) AALLOC_THREAD_ENTER(*pap)
@ -419,41 +453,48 @@ adelete(PArea *pap)
free(bp); free(bp);
} }
#ifdef AALLOC_TRACK #if defined(AALLOC_TRACK) && !defined(AALLOC_STATS)
/* if we are the last TArea allocated */
if (track == *pap) { if (track == *pap) {
(*pap)->prev.iv ^= gcookie; if (isunaligned(ldcook(xp, (*pap)->prev, fcookie))) {
track = (PArea)((*pap)->prev.pv); AALLOC_WARN("AALLOC_TRACK data structure %p destroyed:"
" %p", *pap, xp.cp);
track = NULL;
} else
track = (PArea)xp.cp;
goto adelete_tracked; goto adelete_tracked;
} }
/* find the TArea whose prev is *pap */ /* find the TArea whose prev is *pap */
tp = track; tp = track;
while (tp) { while (tp) {
lp.iv = tp->prev.iv ^ gcookie;
if ((lp.iv & PVMASK)
#ifndef AALLOC_NO_COOKIES #ifndef AALLOC_NO_COOKIES
|| !((tp->ocookie ^ gcookie) & PVMASK) xc = ldcook(xp, tp->scookie, fcookie);
#endif #endif
) { (void)ldcook(xp, tp->prev, fcookie);
if (isunaligned(xp.nv) || !iscook(xc)) {
/* buffer overflow or something? */ /* buffer overflow or something? */
AALLOC_WARN("AALLOC_TRACK data structure %p destroyed:" AALLOC_WARN("AALLOC_TRACK data structure %p destroyed:"
" %p, %p, %p; exiting", tp, lp.pv, tp->bp.pv, " %p, %p; ignoring", tp, xp.cp, (void *)xc);
(void *)(tp->ocookie ^ gcookie));
tp = NULL; tp = NULL;
break; break;
} }
if (lp.pv == (char *)*pap) if (xp.cp == (char *)*pap)
break; break;
tp = (PArea)lp.pv; tp = (PArea)xp.cp;
} }
if (tp) if (tp)
tp->prev.iv = (*pap)->prev.iv; /* decouple *pap */ tp->prev.xv = (*pap)->prev.xv; /* decouple *pap */
else else
AALLOC_WARN("area %p not in found AALLOC_TRACK data structure", AALLOC_WARN("area %p not in found AALLOC_TRACK data structure",
*pap); *pap);
adelete_tracked: adelete_tracked:
#endif #endif
AALLOC_THREAD_LEAVE(*pap) AALLOC_THREAD_LEAVE(*pap)
#ifdef AALLOC_STATS
(*pap)->isfree = true;
#else
free(*pap); free(*pap);
#endif
*pap = NULL; *pap = NULL;
} }
@ -461,11 +502,12 @@ void *
alloc(size_t nmemb, size_t size, PArea ap) alloc(size_t nmemb, size_t size, PArea ap)
{ {
PBlock bp; PBlock bp;
TPtr *ptr; TCooked *rp;
TPtr xp;
/* obtain the memory region requested, retaining guards */ /* obtain the memory region requested, retaining guards */
safe_muladd(nmemb, size, sizeof (TPtr)); safe_muladd(nmemb, size, sizeof (TPtr));
safe_malloc(ptr, size); safe_malloc(rp, size);
AALLOC_THREAD_ENTER(ap) AALLOC_THREAD_ENTER(ap)
@ -473,7 +515,7 @@ alloc(size_t nmemb, size_t size, PArea ap)
if ((bp = check_bp(ap, "alloc", 0)) == NULL) if ((bp = check_bp(ap, "alloc", 0)) == NULL)
AALLOC_ABORT("cannot continue"); AALLOC_ABORT("cannot continue");
if (bp->last == bp->endp) { if (bp->last == bp->endp) {
TPtr **tp; TCooked **pp;
size_t bsz; size_t bsz;
/* make room for more forward ptrs in the block allocation */ /* make room for more forward ptrs in the block allocation */
@ -484,18 +526,18 @@ alloc(size_t nmemb, size_t size, PArea ap)
bp->endp = (char *)bp + bsz; bp->endp = (char *)bp + bsz;
/* all backpointers have to be adjusted */ /* all backpointers have to be adjusted */
for (tp = (TPtr **)&bp->storage; tp < (TPtr **)bp->last; ++tp) { pp = (TCooked **)&bp->storage;
(*tp)->pv = (char *)tp; while (pp < (TCooked **)bp->last) {
(*tp)->iv ^= bp->cookie; (void)stcookp(**pp, pp, bp->bcookie);
++pp;
} }
/* “bp” has possibly changed, enter its new value into ap */ /* “bp” has possibly changed, enter its new value into ap */
ap->bp.pv = (char *)bp; (void)stcookp(ap->bp, bp, fcookie);
ap->bp.iv ^= gcookie;
} }
*((void **)bp->last) = ptr; /* next available forward ptr */ memcpy(bp->last, &rp, PVALIGN); /* next available forward ptr */
ptr->pv = bp->last; /* backpointer to fwdptr storage */ /* store cooked backpointer to address of forward pointer */
ptr->iv ^= bp->cookie; /* apply block cookie */ (void)stcookp(*rp, bp->last, bp->bcookie);
bp->last += PVALIGN; /* advance next-avail pointer */ bp->last += PVALIGN; /* advance next-avail pointer */
#ifdef AALLOC_STATS #ifdef AALLOC_STATS
ap->numalloc++; ap->numalloc++;
@ -511,14 +553,15 @@ alloc(size_t nmemb, size_t size, PArea ap)
AALLOC_THREAD_LEAVE(ap) AALLOC_THREAD_LEAVE(ap)
/* return aligned storage just after the cookied backpointer */ /* return aligned storage just after the cookied backpointer */
return ((char *)ptr + PVALIGN); return ((char *)rp + PVALIGN);
} }
void * void *
aresize(void *vp, size_t nmemb, size_t size, PArea ap) aresize(void *vp, size_t nmemb, size_t size, PArea ap)
{ {
PBlock bp; PBlock bp;
TPtr *ptr; TCooked *rp;
TPtr xp;
if (vp == NULL) if (vp == NULL)
return (alloc(nmemb, size, ap)); return (alloc(nmemb, size, ap));
@ -526,76 +569,86 @@ aresize(void *vp, size_t nmemb, size_t size, PArea ap)
AALLOC_THREAD_ENTER(ap) AALLOC_THREAD_ENTER(ap)
/* validate allocation and backpointer against forward pointer */ /* validate allocation and backpointer against forward pointer */
if ((ptr = check_ptr(vp, ap, &bp, "aresize", "")) == NULL) if ((rp = check_ptr(vp, ap, &bp, &xp, "aresize", "")) == NULL)
AALLOC_ABORT("cannot continue"); AALLOC_ABORT("cannot continue");
/* move allocation to size and possibly new location */ /* move allocation to size and possibly new location */
safe_muladd(nmemb, size, sizeof (TPtr)); safe_muladd(nmemb, size, sizeof (TPtr));
safe_realloc(ptr, size); safe_realloc(rp, size);
/* write new address of allocation into the block forward pointer */ /* write new address of allocation into the block forward pointer */
memcpy(ptr->pv, &ptr, PVALIGN); memcpy(xp.cp, &rp, PVALIGN);
/* apply the cookie on the backpointer again */
ptr->iv ^= bp->cookie;
AALLOC_DENY(bp); AALLOC_DENY(bp);
AALLOC_THREAD_LEAVE(ap) AALLOC_THREAD_LEAVE(ap)
return ((char *)ptr + PVALIGN); return ((char *)rp + PVALIGN);
} }
/* /*
* Try to find vp inside Area ap, use what and extra for error msgs. * Try to find vp inside Area ap, use what and extra for error msgs.
* *
* If an error occurs, returns NULL with no side effects. * If an error occurs, returns NULL with no side effects.
* Otherwise, returns address of the allocation, with the cookie on the * Otherwise, returns address of the allocation, *bpp contains the unlocked
* backpointer unapplied; *bpp contains the unlocked block pointer. * block pointer, *xpp the uncookied backpointer.
*/ */
static TPtr * static TCooked *
check_ptr(void *vp, PArea ap, PBlock *bpp, const char *what, const char *extra) check_ptr(void *vp, PArea ap, PBlock *bpp, TPtr *xpp, const char *what,
const char *extra)
{ {
PBlock bp; TCooked *rp;
TPtr *ptr;
if ((ptrdiff_t)vp & PVMASK) { #ifndef AALLOC_SMALL
if (isunaligned(vp)) {
AALLOC_WARN("trying to %s rogue unaligned pointer %p from " AALLOC_WARN("trying to %s rogue unaligned pointer %p from "
"area %p%s", what + 1, vp, ap, extra); "area %p%s", what + 1, vp, ap, extra);
return (NULL); return (NULL);
} }
#endif
ptr = (TPtr *)((char *)vp - PVALIGN); rp = (TCooked *)(((char *)vp) - PVALIGN);
if (!ptr->iv) { #ifndef AALLOC_SMALL
if (!rp->xv) {
AALLOC_WARN("trying to %s already freed pointer %p from " AALLOC_WARN("trying to %s already freed pointer %p from "
"area %p%s", what + 1, vp, ap, extra); "area %p%s", what + 1, vp, ap, extra);
return (NULL); return (NULL);
} }
#endif
if ((bp = check_bp(ap, what, 0)) == NULL) if ((*bpp = check_bp(ap, what, 0)) == NULL)
AALLOC_ABORT("cannot continue"); AALLOC_ABORT("cannot continue");
ptr->iv ^= bp->cookie; #ifndef AALLOC_SMALL
if (ptr->pv < (char *)&bp->storage || ptr->pv >= bp->last) { if (isunaligned(ldcook(*xpp, *rp, (*bpp)->bcookie))) {
AALLOC_WARN("trying to %s rogue pointer %p from area %p "
"(block %p..%p), backpointer %p unaligned%s",
what + 1, vp, ap, *bpp, (*bpp)->last, xpp->cp, extra);
} else if (xpp->cp < (char *)&(*bpp)->storage ||
xpp->cp >= (*bpp)->last) {
AALLOC_WARN("trying to %s rogue pointer %p from area %p " AALLOC_WARN("trying to %s rogue pointer %p from area %p "
"(block %p..%p), backpointer %p out of bounds%s", "(block %p..%p), backpointer %p out of bounds%s",
what + 1, vp, ap, bp, bp->last, ptr->pv, extra); what + 1, vp, ap, *bpp, (*bpp)->last, xpp->cp, extra);
AALLOC_DENY(bp); } else if (*((TCooked **)xpp->cp) != rp) {
return (NULL);
}
if (*((void **)ptr->pv) != ptr) {
AALLOC_WARN("trying to %s rogue pointer %p from area %p " AALLOC_WARN("trying to %s rogue pointer %p from area %p "
"(block %p..%p), backpointer %p, forward pointer to " "(block %p..%p), backpointer %p, forward pointer to "
"%p instead%s", what + 1, vp, ap, bp, bp->last, "%p instead%s", what + 1, vp, ap, *bpp, (*bpp)->last,
ptr->pv, *((void **)ptr->pv), extra); xpp->cp, *((TCooked **)xpp->cp), extra);
AALLOC_DENY(bp); } else
#endif
return (rp);
#ifndef AALLOC_SMALL
/* error case fall-through */
AALLOC_DENY(*bpp);
return (NULL); return (NULL);
} #endif
*bpp = bp;
return (ptr);
} }
void void
afree(void *vp, PArea ap) afree(void *vp, PArea ap)
{ {
PBlock bp; PBlock bp;
TPtr *ptr; TCooked *rp;
TPtr xp;
if (vp == NULL) if (vp == NULL)
return; return;
@ -603,23 +656,20 @@ afree(void *vp, PArea ap)
AALLOC_THREAD_ENTER(ap) AALLOC_THREAD_ENTER(ap)
/* validate allocation and backpointer, ignore rogues */ /* validate allocation and backpointer, ignore rogues */
if ((ptr = check_ptr(vp, ap, &bp, "afree", ", ignoring")) == NULL) if ((rp = check_ptr(vp, ap, &bp, &xp, "afree", ", ignoring")) == NULL)
goto afree_done; goto afree_done;
/* note: the block allocation does not ever shrink */ /* note: the block allocation does not ever shrink */
bp->last -= PVALIGN; /* mark the last forward pointer as free */ bp->last -= PVALIGN; /* mark the last forward pointer as free */
/* if our forward pointer was not the last one, relocate the latter */ /* if our forward pointer was not the last one, relocate the latter */
if (ptr->pv < bp->last) { if (xp.cp < bp->last) {
TPtr *tmp = *((TPtr **)bp->last); TCooked *tmp = *((TCooked **)bp->last);
/* tmp is the former last forward pointer */ (void)stcook(*tmp, xp, bp->bcookie); /* write new backptr */
tmp->pv = ptr->pv; /* its backpointer to former our … */ memcpy(xp.cp, bp->last, PVALIGN); /* relocate fwd ptr */
tmp->iv ^= bp->cookie; /* … forward pointer, and cookie it */
memcpy(ptr->pv, bp->last, PVALIGN); /* relocate fwd ptr */
} }
ptr->iv = 0; /* our backpointer, just in case, for double frees */ rp->xv = 0; /* our backpointer, just in case, for double frees */
free(ptr); free(rp);
AALLOC_DENY(bp); AALLOC_DENY(bp);
afree_done: afree_done: