From 7cfe69417cad6dc797729aaa60dc538aa194e1ba Mon Sep 17 00:00:00 2001 From: "David E. O'Brien" Date: Wed, 13 Oct 2010 23:29:09 +0000 Subject: [PATCH] Do not assume in growstackstr() that a "precious" character will be immediately written into the stack after the call. Instead let the caller manage the "space left". Previously, growstackstr()'s assumption causes problems with STACKSTRNUL() where we want to be able to turn a stack into a C string, and later pretend the NUL is not there. This fixes a bug in STACKSTRNUL() (that grew the stack) where: 1. STADJUST() called after a STACKSTRNUL() results in an improper adjust. This can be seen in ${var%pattern} and ${var%%pattern} evaluation. 2. Memory leak in STPUTC() called after a STACKSTRNUL(). Reviewed by: jilles --- bin/sh/histedit.c | 2 +- bin/sh/memalloc.c | 17 ++++++++++------- bin/sh/memalloc.h | 9 ++++++++- tools/regression/bin/sh/expansion/trim4.0 | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 tools/regression/bin/sh/expansion/trim4.0 diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c index 7773ad8d5ff..dab69f1b16b 100644 --- a/bin/sh/histedit.c +++ b/bin/sh/histedit.c @@ -418,7 +418,7 @@ fc_replace(const char *s, char *p, char *r) } else STPUTC(*s++, dest); } - STACKSTRNUL(dest); + STPUTC('\0', dest); dest = grabstackstr(dest); return (dest); diff --git a/bin/sh/memalloc.c b/bin/sh/memalloc.c index 01bddb2b1ff..91587197f92 100644 --- a/bin/sh/memalloc.c +++ b/bin/sh/memalloc.c @@ -295,6 +295,13 @@ grabstackblock(int len) * is space for at least one character. */ +static char * +growstrstackblock(int n) +{ + growstackblock(); + sstrnleft = stackblocksize() - n; + return stackblock() + n; +} char * growstackstr(void) @@ -304,12 +311,10 @@ growstackstr(void) len = stackblocksize(); if (herefd >= 0 && len >= 1024) { xwrite(herefd, stackblock(), len); - sstrnleft = len - 1; + sstrnleft = len; return stackblock(); } - growstackblock(); - sstrnleft = stackblocksize() - len - 1; - return stackblock() + len; + return growstrstackblock(len); } @@ -323,9 +328,7 @@ makestrspace(void) int len; len = stackblocksize() - sstrnleft; - growstackblock(); - sstrnleft = stackblocksize() - len; - return stackblock() + len; + return growstrstackblock(len); } diff --git a/bin/sh/memalloc.h b/bin/sh/memalloc.h index 187d4c855af..563927aeb57 100644 --- a/bin/sh/memalloc.h +++ b/bin/sh/memalloc.h @@ -67,9 +67,16 @@ void ungrabstackstr(char *, char *); #define stackblock() stacknxt #define stackblocksize() stacknleft #define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() -#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) +#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), --sstrnleft, *p++ = (c))) #define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } #define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) +/* + * STACKSTRNUL's use is where we want to be able to turn a stack + * (non-sentinel, character counting string) into a C string, + * and later pretend the NUL is not there. + * Note: Because of STACKSTRNUL's semantics, STACKSTRNUL cannot be used + * on a stack that will grabstackstr()ed. + */ #define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) #define STUNPUTC(p) (++sstrnleft, --p) #define STTOPC(p) p[-1] diff --git a/tools/regression/bin/sh/expansion/trim4.0 b/tools/regression/bin/sh/expansion/trim4.0 new file mode 100644 index 00000000000..1000bd3d024 --- /dev/null +++ b/tools/regression/bin/sh/expansion/trim4.0 @@ -0,0 +1,15 @@ +# $FreeBSD$ + +v1=/homes/SOME_USER +v2= +v3=C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 + +# Trigger bug in VSTRIMRIGHT processing STADJUST() call in expand.c:subevalvar() +while [ ${#v2} -lt 2000 ]; do + v4="${v2} ${v1%/*} $v3" + if [ ${#v4} -ne $((${#v2} + ${#v3} + 8)) ]; then + echo bad: ${#v4} -ne $((${#v2} + ${#v3} + 8)) + fi + v2=x$v2 + v3=y$v3 +done