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
This commit is contained in:
David E. O'Brien 2010-10-13 23:29:09 +00:00
parent bf73d4d28e
commit 7cfe69417c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213814
4 changed files with 34 additions and 9 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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]

View File

@ -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