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:
parent
1ca9790f1d
commit
90e8e7ea72
4
Makefile
4
Makefile
@ -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
314
aalloc.c
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user