Module Name:    src
Committed By:   rillig
Date:           Sun Jul 19 22:04:28 UTC 2020

Modified Files:
        src/usr.bin/make: var.c
        src/usr.bin/make/unit-tests: sysv.exp sysv.mk

Log Message:
make(1): make ampersand in ${VAR:from=to&} an ordinary character

In SysV substitutions, wildcards are expressed with % instead of &.  The
& is not mentioned in the manual page, and having another wildcard for
the whole word would be such an obscure feature that not even pkgsrc uses
it.  The easiest way to discover this feature had been to read the source
code of make(1) or to use a fuzzer and accidentally stumble upon this
edge case.


To generate a diff of this commit:
cvs rdiff -u -r1.275 -r1.276 src/usr.bin/make/var.c
cvs rdiff -u -r1.5 -r1.6 src/usr.bin/make/unit-tests/sysv.exp
cvs rdiff -u -r1.6 -r1.7 src/usr.bin/make/unit-tests/sysv.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.275 src/usr.bin/make/var.c:1.276
--- src/usr.bin/make/var.c:1.275	Sun Jul 19 21:30:49 2020
+++ src/usr.bin/make/var.c	Sun Jul 19 22:04:27 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.275 2020/07/19 21:30:49 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.276 2020/07/19 22:04:27 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.275 2020/07/19 21:30:49 rillig Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.276 2020/07/19 22:04:27 rillig Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: var.c,v 1.275 2020/07/19 21:30:49 rillig Exp $");
+__RCSID("$NetBSD: var.c,v 1.276 2020/07/19 22:04:27 rillig Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -1308,22 +1308,27 @@ Str_SYSVSubst(Buffer *buf, const char *p
 }
 
 
+typedef struct {
+    const char *lhs;
+    const char *rhs;
+} VarSYSVSubstArgs;
+
 /* Callback function for VarModify to implement the :%.from=%.to modifier. */
 static Boolean
-VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
+VarSYSVSubst(GNode *ctx, Var_Parse_State *vpstate,
 	     const char *word, Boolean addSpace, Buffer *buf,
 	     void *data)
 {
-    size_t len;
-    const char *ptr;
-    Boolean hasPercent;
-    VarPattern *pat = data;
+    const VarSYSVSubstArgs *args = data;
 
     if (addSpace && vpstate->varSpace != '\0')
 	Buf_AddByte(buf, vpstate->varSpace);
 
-    if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
-	char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARE_WANTRES);
+    size_t len;
+    Boolean hasPercent;
+    const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent);
+    if (ptr != NULL) {
+	char *varexp = Var_Subst(NULL, args->rhs, ctx, VARE_WANTRES);
 	Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
 	free(varexp);
     } else {
@@ -3167,15 +3172,7 @@ ApplyModifier_Remember(ApplyModifiersSta
 static int
 ApplyModifier_SysV(ApplyModifiersState *st)
 {
-    /*
-     * This can either be a bogus modifier or a System-V
-     * substitution command.
-     */
-    VarPattern      pattern;
-    /* FIXME: SysV modifiers have nothing to do with :S or :C pattern matching */
-    Boolean         eqFound = FALSE;
-
-    pattern.pflags = 0;
+    Boolean eqFound = FALSE;
 
     /*
      * First we make a pass through the string trying
@@ -3200,20 +3197,19 @@ ApplyModifier_SysV(ApplyModifiersState *
 
     st->delim = '=';
     st->cp = st->tstr;
+    VarPatternFlags pflags = 0;
     /* FIXME: There's no point in having a single $ at the end of a
      * SysV substitution since that will not be interpreted as an
      * anchor anyway. */
-    pattern.lhs = ParseModifierPart(
-	st->ctxt, &st->cp, st->delim, st->eflags,
-	&pattern.pflags, &pattern.leftLen, NULL);
-    if (pattern.lhs == NULL)
+    char *lhs = ParseModifierPart(st->ctxt, &st->cp, st->delim, st->eflags,
+				  &pflags, NULL, NULL);
+    if (lhs == NULL)
 	return 'c';
 
     st->delim = st->endc;
-    pattern.rhs = ParseModifierPart(
-	st->ctxt, &st->cp, st->delim, st->eflags,
-	NULL, &pattern.rightLen, &pattern);
-    if (pattern.rhs == NULL)
+    char *rhs = ParseModifierPart(st->ctxt, &st->cp, st->delim, st->eflags,
+				  NULL, NULL, NULL);
+    if (rhs == NULL)
 	return 'c';
 
     /*
@@ -3222,14 +3218,15 @@ ApplyModifier_SysV(ApplyModifiersState *
      */
     st->termc = *--st->cp;
     st->delim = '\0';
-    if (pattern.leftLen == 0 && *st->nstr == '\0') {
+    if (lhs[0] == '\0' && *st->nstr == '\0') {
 	st->newStr = st->nstr;	/* special case */
     } else {
-	st->newStr = VarModify(
-	    st->ctxt, &st->parsestate, st->nstr, VarSYSVMatch, &pattern);
+	VarSYSVSubstArgs args = { lhs, rhs };
+	st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr,
+			       VarSYSVSubst, &args);
     }
-    free(UNCONST(pattern.lhs));
-    free(UNCONST(pattern.rhs));
+    free(lhs);
+    free(rhs);
     return '=';
 }
 #endif

Index: src/usr.bin/make/unit-tests/sysv.exp
diff -u src/usr.bin/make/unit-tests/sysv.exp:1.5 src/usr.bin/make/unit-tests/sysv.exp:1.6
--- src/usr.bin/make/unit-tests/sysv.exp:1.5	Sun Jul 19 14:23:02 2020
+++ src/usr.bin/make/unit-tests/sysv.exp	Sun Jul 19 22:04:27 2020
@@ -14,5 +14,5 @@ a.c.c
 
 ax:Q b c d eb
 bcd.e
-a.bcd.e
+&
 exit status 0

Index: src/usr.bin/make/unit-tests/sysv.mk
diff -u src/usr.bin/make/unit-tests/sysv.mk:1.6 src/usr.bin/make/unit-tests/sysv.mk:1.7
--- src/usr.bin/make/unit-tests/sysv.mk:1.6	Sun Jul 19 14:23:02 2020
+++ src/usr.bin/make/unit-tests/sysv.mk	Sun Jul 19 22:04:27 2020
@@ -1,4 +1,4 @@
-# $Id: sysv.mk,v 1.6 2020/07/19 14:23:02 rillig Exp $
+# $Id: sysv.mk,v 1.7 2020/07/19 22:04:27 rillig Exp $
 
 all: foo fun sam bla words ampersand
 
@@ -47,10 +47,10 @@ bla:
 words:
 	@echo a${a b c d e:L:%a=x:Q}b
 
-# As of 2020-07-19, an ampersand can be used in the replacement part
-# of a SysV substitution modifier.  This can either be an intentional
-# feature or an implementation mistake, as it is not mentioned in the
-# manual page.
+# Before 2020-07-19, an ampersand could be used in the replacement part
+# of a SysV substitution modifier.  This was probably a copy-and-paste
+# mistake since the SysV modifier code looked a lot like the code for the
+# :S and :C modifiers.  The ampersand is not mentioned in the manual page.
 ampersand:
 	@echo ${:U${a.bcd.e:L:a.%=%}:Q}
 	@echo ${:U${a.bcd.e:L:a.%=&}:Q}

Reply via email to