[SV 64822, SV 36486] Fix appending to a pattern specific variable

Appending to a pattern specific variable produces an incorrect value
in the presence of a command line definition or an env override of
the variable.  Also, fix pattern/target-specific appending to a
variable with origin override.

* At parse time record_target_var sets the value of a pattern
  specific variable to the value defined on command line or to the
  value of the env override.
* Later, at build time, recursively_expand_for_file appends this
  value of the variable (set in record_target_var) to the command
  line value again, regardless of the origin of the variable.

This patch modifies recursively_expand_for_file to avoid appending,
unless the origin of the variable beats or equals the origin of one
of the parent definitions of this variable.

Reported by Rob <robw9739@gmail.com>,
Brian Vandenberg <phantall@gmail.com>,
Markus Oberhumer <markus@oberhumer.com>.

* NEWS: Note the change.
* src/variable.c (do_variable_definition): Avoid merging a
pattern-specific variable with the parent definition when a command
line or env override is present.
* src/expand.c (recursively_expand_for_file): Avoid appending to a
pattern-specific variable, unless the origin of this pattern-specific
variable beats or equals the origin of one of the parent definitions
of this variable.
* doc/make.texi (Override Directive): Add missing cross-reference.
* tests/scripts/variables/append: Add tests.
This commit is contained in:
Dmitry Goncharov
2024-02-04 13:04:05 -05:00
committed by Paul Smith
parent a493d9ab6c
commit 07187db947
5 changed files with 370 additions and 23 deletions

View File

@@ -148,13 +148,14 @@ recursively_expand_for_file (struct variable *v, struct file *file)
const floc **saved_varp;
struct variable_set_list *savev = 0;
int set_reading = 0;
size_t nl = strlen (v->name);
struct variable *parent = NULL;
/* If we're expanding to put into the environment of a shell function then
ignore any recursion issues: for backward-compatibility we will use
the value of the environment variable we were started with. */
if (v->expanding && env_recursion)
{
size_t nl = strlen (v->name);
char **ep;
DB (DB_VERBOSE,
(_("%s:%lu: not recursively expanding %s to export to shell function\n"),
@@ -203,8 +204,49 @@ recursively_expand_for_file (struct variable *v, struct file *file)
v->expanding = 1;
if (v->append)
{
/* Find a parent definition which is marked override. */
struct variable_set_list *sl;
for (sl = current_variable_set_list; sl && !parent; sl = sl->next)
{
struct variable *vp = lookup_variable_in_set (v->name, nl, sl->set);
if (vp && vp != v && vp->origin == o_override)
parent = vp;
}
}
if (parent)
/* PARENT is an override, V is appending. If V is also an override:
override hello := first
al%: override hello += second
Then construct the value from its appended parts in the parent sets.
Else if V is not an override:
override hello := first
al%: hello += second
Then ignore the value of V and use the value of PARENT. */
value = v->origin == o_override
? allocated_variable_append (v)
: xstrdup (parent->value);
else if (v->origin == o_command || v->origin == o_env_override)
/* Avoid appending to a pattern-specific variable, unless the origin of this
pattern-specific variable beats or equals the origin of one of the parent
definitions of this variable.
This is needed, because if there is a command line definition or an env
override, then the value defined in the makefile should only be appended
in the case of a file override.
In the presence of command line definition or env override and absence of
makefile override, the value should be expanded, rather than appended. In
this case, at parse time record_target_var already set the value of this
pattern-specific variable to the value defined on the command line or to
the env override value.
User provided a command line definition or an env override.
PARENT does not have an override directive, so ignore it. */
value = allocated_expand_string (v->value);
else if (v->append)
/* Construct the value from its appended parts in the parent sets. */
value = allocated_variable_append (v);
else
/* A definition without appending. */
value = allocated_expand_string (v->value);
v->expanding = 0;

View File

@@ -1432,29 +1432,56 @@ do_variable_definition (const floc *flocp, const char *varname, const char *valu
case f_append:
case f_append_value:
{
/* If we have += but we're in a target variable context, we want to
append only with other variables in the context of this target. */
if (scope)
int override = 0;
if (scope == s_global)
v = lookup_variable (varname, strlen (varname));
else
{
/* When appending in a target/pattern variable context, we want to
append only with other variables in the context of this
target/pattern. */
append = 1;
v = lookup_variable_in_set (varname, strlen (varname),
current_variable_set_list->set);
if (v)
{
/* Don't append from the global set if a previous non-appending
target/pattern-specific variable definition exists. */
if (!v->append)
append = 0;
/* Don't append from the global set if a previous non-appending
target-specific variable definition exists. */
if (v && !v->append)
append = 0;
if (scope == s_pattern &&
(v->origin == o_env_override || v->origin == o_command))
{
/* This is the case of multiple target/pattern specific
definitions/appends, e.g.
al%: hello := first
al%: hello += second
in the presence of a command line definition or an
env override. Do not merge x->value and value here.
For pattern-specific variables the values are merged in
recursively_expand_for_file. */
override = 1;
append = 1;
}
}
}
else
v = lookup_variable (varname, strlen (varname));
if (v == 0)
if (!v)
{
/* There was no old value.
This becomes a normal recursive definition. */
/* There was no old value: make this a recursive definition. */
newval = value;
flavor = f_recursive;
}
else if (override)
{
/* Command line definition / env override takes precedence over
a pattern/target-specific append. */
newval = value;
/* Set flavor to f_recursive to recursively expand this variable
at build time in recursively_expand_for_file. */
flavor = f_recursive;
}
else
{
/* Paste the old and new values together in VALUE. */