[SV 54161] Fix second expansion of $* for paths
If the stem matches a path containing a directory not just a
filename, make sure the second expansion of $* in the
prerequisites matches $* in the recipe. This requires using
$(*F) when replacing % in the first expansion to preserve the
simple filename.
* src/implicit.c (pattern_search): If lastslash is set prepend
the directory onto the stem. Then use $(*F) when expanding %.
* tests/scripts/features/se_implicit: Add a test case
diff --git a/src/implicit.c b/src/implicit.c
index cd707b2..f7b8c15 100644
--- a/src/implicit.c
+++ b/src/implicit.c
@@ -220,8 +220,9 @@
struct patdeps *deplist = xmalloc (max_deps * sizeof (struct patdeps));
struct patdeps *pat = deplist;
- /* Names of possible dependencies are constructed in this buffer. */
- char *depname = alloca (namelen + max_pattern_dep_length);
+ /* Names of possible dependencies are constructed in this buffer.
+ We may replace % by $(*F) for second expansion, increasing the length. */
+ char *depname = alloca (namelen + max_pattern_dep_length + 4);
/* The start and length of the stem of FILENAME for the current rule. */
const char *stem = 0;
@@ -477,9 +478,10 @@
}
}
- if (stemlen > GET_PATH_MAX)
+ if (stemlen + (check_lastslash ? pathlen : 0) > GET_PATH_MAX)
{
- DBS (DB_IMPLICIT, (_("Stem too long: '%.*s'.\n"),
+ DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"),
+ check_lastslash ? pathdir : "",
(int) stemlen, stem));
continue;
}
@@ -487,8 +489,19 @@
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"),
(int) stemlen, stem));
- strncpy (stem_str, stem, stemlen);
- stem_str[stemlen] = '\0';
+ if (!check_lastslash)
+ {
+ memcpy (stem_str, stem, stemlen);
+ stem_str[stemlen] = '\0';
+ }
+ else
+ {
+ /* We want to prepend the directory from
+ the original FILENAME onto the stem. */
+ memcpy (stem_str, filename, pathlen);
+ memcpy (stem_str + pathlen, stem, stemlen);
+ stem_str[pathlen + stemlen] = '\0';
+ }
/* If there are no prerequisites, then this rule matches. */
if (rule->deps == 0)
@@ -539,7 +552,7 @@
}
memcpy (o, nptr, p - nptr);
o += p - nptr;
- memcpy (o, stem_str, stemlen);
+ memcpy (o, stem, stemlen);
o += stemlen;
strcpy (o, p + 1);
}
@@ -590,10 +603,10 @@
again. This is not good if you have certain characters
in your stem (like $).
- Instead, we will replace % with $* and allow the second
- expansion to take care of it for us. This way (since $*
- is a simple variable) there won't be additional
- re-expansion of the stem. */
+ Instead, we will replace % with $* or $(*F) and allow the
+ second expansion to take care of it for us. This way
+ (since $* and $(*F) are simple variables) there won't be
+ additional re-expansion of the stem. */
p = lindex (nptr, nptr + len, '%');
if (p == 0)
@@ -604,13 +617,22 @@
else
{
size_t i = p - nptr;
- memcpy (depname, nptr, i);
- memcpy (depname + i, "$*", 2);
- memcpy (depname + i + 2, p + 1, len - i - 1);
- depname[len + 2 - 1] = '\0';
-
+ char *o = depname;
+ memcpy (o, nptr, i);
+ o += i;
if (check_lastslash)
- add_dir = 1;
+ {
+ add_dir = 1;
+ memcpy (o, "$(*F)", 5);
+ o += 5;
+ }
+ else
+ {
+ memcpy (o, "$*", 2);
+ o += 2;
+ }
+ memcpy (o, p + 1, len - i - 1);
+ o[len - i - 1] = '\0';
}
/* Set up for the next word. */
diff --git a/tests/scripts/features/se_implicit b/tests/scripts/features/se_implicit
index a01b385..866d1fb 100644
--- a/tests/scripts/features/se_implicit
+++ b/tests/scripts/features/se_implicit
@@ -254,5 +254,13 @@
!,
'', "bar\n#MAKE#: Nothing to be done for 'foo'.\n");
+# SV 54161: Expand $$* properly when it contains a path
+
+run_make_test(q!
+.SECONDEXPANSION:
+%x: $$(info $$*); @echo '$*'
+!,
+ 'q/ux', "q/u\nq/u\n");
+
# This tells the test driver that the perl test script executed properly.
1;