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:
		
							
								
								
									
										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 \ | ||||||
|   | |||||||
							
								
								
									
										322
									
								
								aalloc.c
									
									
									
									
									
								
							
							
						
						
									
										322
									
								
								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(); | ||||||
| 			v = AALLOC_RANDOM() & 7; | 			if (AALLOC_RANDOM() & 1) | ||||||
| 		} while (!(global_cookie & PVMASK) || !v); | 				v = AALLOC_RANDOM() & 7; | ||||||
|  | 		} 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 | ||||||
| 		return (NULL); | #endif | ||||||
| 	} | 		return (rp); | ||||||
| 	*bpp = bp; |  | ||||||
| 	return (ptr); | #ifndef AALLOC_SMALL | ||||||
|  | 	/* error case fall-through */ | ||||||
|  | 	AALLOC_DENY(*bpp); | ||||||
|  | 	return (NULL); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| 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: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user