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}