Fix a buffer over-read of an unfinished macro "%{!" expansion

Problem was in a buffer over-read of the memory right after
the end of the allocated area when expanding of an unfinished macro
starting "%{" that can contain only exclamation marks and question
marks. Like "%{", or "%{!", or "%{??!".

Similar problem as in commit 54f24ec548
with the difference that this problem was not found by a memory
sanitizer.

This is a good opportunity to refactor the corresponding code
(setting variables according to the number of exclamation marks and
question mark after % an before the macro).
This commit is contained in:
Pavlina Moravcova Varekova 2019-05-07 12:21:51 +02:00 committed by Panu Matilainen
parent 57899bd3bf
commit 03909fc4d3
1 changed files with 16 additions and 22 deletions

View File

@ -1174,6 +1174,20 @@ static void doTrace(MacroBuf mb, int chkexist, int negate,
}
}
static const char *setNegateAndCheck(const char *str, int *pnegate, int *pchkexist) {
*pnegate = 0;
*pchkexist = 0;
while ((*str == '?') || (*str == '!')) {
if (*str == '!')
*pnegate = !*pnegate;
else
(*pchkexist)++;
str++;
}
return str;
}
/**
* The main macro recursion loop.
* @param mb macro expansion state
@ -1255,21 +1269,10 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
g = ge = NULL;
if (mb->depth > 1) /* XXX full expansion for outermost level */
tpos = mb->tpos; /* save expansion pointer for printExpand */
negate = 0;
lastc = NULL;
chkexist = 0;
switch ((c = *s)) {
default: /* %name substitution */
while (*s != '\0' && strchr("!?", *s) != NULL) {
switch (*s++) {
case '!':
negate = ((negate + 1) % 2);
break;
case '?':
chkexist++;
break;
}
}
s = setNegateAndCheck(s, &negate, &chkexist);
f = se = s;
if (*se == '-')
se++;
@ -1317,16 +1320,7 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
}
f = s+1;/* skip { */
se++; /* skip } */
while (strchr("!?", *f) != NULL) {
switch (*f++) {
case '!':
negate = ((negate + 1) % 2);
break;
case '?':
chkexist++;
break;
}
}
f = setNegateAndCheck(f, &negate, &chkexist);
for (fe = f; (c = *fe) && !strchr(" :}", c);)
fe++;
switch (c) {