Fix multiply defined local macros escaping scope

freeArgs() only popped any local macros once, so if a local macro was
pushed multiple times, whether through %define or multiple identical
options getting passed, we leaked any remaining macros to the outside
scope.

Simply pop the local macros in a loop to fix. Have the internal
popMacro() return the previous pointer (if any) to simplify the job.
We even had an expected-fail test for this, now passing, but add a
more straightforward reproducer too.

This bug was circa 26 years old. Some might call it vintage at this point.

Fixes: #3056
This commit is contained in:
Panu Matilainen 2024-04-24 10:23:48 +03:00 committed by Florian Festi
parent e6d6b49f2f
commit 695b5c2521
2 changed files with 21 additions and 8 deletions

View File

@ -139,7 +139,7 @@ static int expandMacro(rpmMacroBuf mb, const char *src, size_t slen);
static int expandQuotedMacro(rpmMacroBuf mb, const char *src);
static void pushMacro(rpmMacroContext mc,
const char * n, const char * o, const char * b, int level, int flags);
static void popMacro(rpmMacroContext mc, const char * n);
static rpmMacroEntry popMacro(rpmMacroContext mc, const char * n);
static int loadMacroFile(rpmMacroContext mc, const char * fn);
/* =============================================================== */
@ -948,10 +948,13 @@ freeArgs(rpmMacroBuf mb)
me->flags |= ME_USED;
}
/* compensate if the slot is to go away */
if (me->prev == NULL)
while ((me = popMacro(mc, me->name))) {
if (me->level < mb->level)
break;
}
/* compensate if the slot went away */
if (me == NULL)
i--;
popMacro(mc, me->name);
}
mb->level--;
mb->args = NULL;
@ -1867,17 +1870,18 @@ static void pushMacro(rpmMacroContext mc,
return pushMacroAny(mc, n, o, b, NULL, NULL, 0, level, flags);
}
static void popMacro(rpmMacroContext mc, const char * n)
/* Return pointer to the _previous_ macro definition (or NULL) */
static rpmMacroEntry popMacro(rpmMacroContext mc, const char * n)
{
size_t pos;
rpmMacroEntry *mep = findEntry(mc, n, 0, &pos);
if (mep == NULL)
return;
return NULL;
/* parting entry */
rpmMacroEntry me = *mep;
assert(me);
/* detach/pop definition */
mc->tab[pos] = me->prev;
rpmMacroEntry prev = mc->tab[pos] = me->prev;
/* shrink macro table */
if (me->prev == NULL) {
mc->n--;
@ -1889,6 +1893,7 @@ static void popMacro(rpmMacroContext mc, const char * n)
}
/* comes in a single chunk */
free(me);
return prev;
}
static int defineMacro(rpmMacroContext mc, const char * macro, int level)

View File

@ -1087,7 +1087,6 @@ RPMTEST_CLEANUP
AT_SETUP([%define + %undefine in nested levels 3])
AT_KEYWORDS([macros define])
RPMTEST_CHECK([
AT_XFAIL_IF([test $RPM_XFAIL -ne 0])
# %define macro twice in a nested scope
runroot rpm \
--define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand: %define xxx 2} %{echo:%xxx}' \
@ -1100,6 +1099,15 @@ runroot rpm \
. .
%xxx
])
RPMTEST_CHECK([
runroot rpm --define "aa 0" --define "my() %{define:aa 1}%{define:aa 2}" --eval "%my" --eval "%aa"
],
[0],
[
0
],
[ignore])
RPMTEST_CLEANUP
AT_SETUP([%define + %undefine in nested levels 4])