Module Name: src
Committed By: rillig
Date: Sun Dec 27 22:29:37 UTC 2020
Modified Files:
src/usr.bin/make: parse.c
src/usr.bin/make/unit-tests: var-op-expand.mk
Log Message:
make(1): fix edge case in := with undefined in variable name
Previously, the assignment "VAR${UNDEF} := value" actually assigned to 2
variables. See var-op-expand.mk for details.
To generate a diff of this commit:
cvs rdiff -u -r1.519 -r1.520 src/usr.bin/make/parse.c
cvs rdiff -u -r1.7 -r1.8 src/usr.bin/make/unit-tests/var-op-expand.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/parse.c
diff -u src/usr.bin/make/parse.c:1.519 src/usr.bin/make/parse.c:1.520
--- src/usr.bin/make/parse.c:1.519 Sun Dec 27 18:22:28 2020
+++ src/usr.bin/make/parse.c Sun Dec 27 22:29:37 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.519 2020/12/27 18:22:28 rillig Exp $ */
+/* $NetBSD: parse.c,v 1.520 2020/12/27 22:29:37 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -117,7 +117,7 @@
#include "pathnames.h"
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.519 2020/12/27 18:22:28 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.520 2020/12/27 22:29:37 rillig Exp $");
/* types and constants */
@@ -1931,17 +1931,6 @@ VarAssign_EvalSubst(const char *name, co
char *evalue;
Boolean savedPreserveUndefined = preserveUndefined;
- /* TODO: Can this assignment to preserveUndefined be moved further down
- * to the actually interesting Var_Subst call, without affecting any
- * edge cases?
- *
- * It might affect the implicit expansion of the variable name in the
- * Var_Exists and Var_Set calls, even though it's unlikely that anyone
- * cared about this edge case when adding this code. In addition,
- * variable assignments should not refer to any undefined variables in
- * the variable name. */
- preserveUndefined = TRUE;
-
/*
* make sure that we set the variable the first time to nothing
* so that it gets substituted!
@@ -1949,9 +1938,11 @@ VarAssign_EvalSubst(const char *name, co
if (!Var_Exists(name, ctxt))
Var_Set(name, "", ctxt);
+ preserveUndefined = TRUE;
(void)Var_Subst(uvalue, ctxt, VARE_WANTRES | VARE_KEEP_DOLLAR, &evalue);
- /* TODO: handle errors */
preserveUndefined = savedPreserveUndefined;
+ /* TODO: handle errors */
+
avalue = evalue;
Var_Set(name, avalue, ctxt);
Index: src/usr.bin/make/unit-tests/var-op-expand.mk
diff -u src/usr.bin/make/unit-tests/var-op-expand.mk:1.7 src/usr.bin/make/unit-tests/var-op-expand.mk:1.8
--- src/usr.bin/make/unit-tests/var-op-expand.mk:1.7 Sun Dec 27 21:31:27 2020
+++ src/usr.bin/make/unit-tests/var-op-expand.mk Sun Dec 27 22:29:37 2020
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-expand.mk,v 1.7 2020/12/27 21:31:27 rillig Exp $
+# $NetBSD: var-op-expand.mk,v 1.8 2020/12/27 22:29:37 rillig Exp $
#
# Tests for the := variable assignment operator, which expands its
# right-hand side.
@@ -116,26 +116,25 @@ VAR:= top:$$ ${:Unest1\:\$\$} ${:Unest2
.endif
-# XXX: edge case: When a variable name refers to an undefined variable, the
-# behavior differs between the '=' and the ':=' assignment operators.
-# This bug exists since var.c 1.42 from 2000-05-11.
-#
-# The '=' operator expands the undefined variable to an empty string, thus
-# assigning to VAR_ASSIGN_. In the name of variables to be set, it should
-# really be forbidden to refer to undefined variables.
-#
-# The ':=' operator expands the variable name twice. In one of these
-# expansions, the undefined variable expression is preserved (controlled by
-# preserveUndefined in VarAssign_EvalSubst), in the other expansion it expands
-# to an empty string. This way, 2 variables are created using a single
-# variable assignment. It's magic. :-/
+# Between var.c 1.42 from 2000-05-11 and before parse.c 1.520 from 2020-12-27,
+# if the variable name in a ':=' assignment referred to an undefined variable,
+# there were actually 2 assignments to different variables:
+#
+# Global["VAR_SUBST_${UNDEF}"] = ""
+# Global["VAR_SUBST_"] = ""
+#
+# The variable name with the empty value actually included a dollar sign.
+# Variable names with dollars are not used in practice.
+#
+# It might be a good idea to forbid undefined variables on the left-hand side
+# of a variable assignment.
.undef UNDEF
VAR_ASSIGN_${UNDEF}= assigned by '='
VAR_SUBST_${UNDEF}:= assigned by ':='
.if ${VAR_ASSIGN_} != "assigned by '='"
. error
.endif
-.if ${${:UVAR_SUBST_\${UNDEF\}}} != ""
+.if defined(${:UVAR_SUBST_\${UNDEF\}})
. error
.endif
.if ${VAR_SUBST_} != "assigned by ':='"