Sat Aug 22 20:31:50 2020 UTC ()
make(1): prevent assignment to the variable with the empty name


(rillig)
diff -r1.457 -r1.458 src/usr.bin/make/var.c
diff -r1.1 -r1.2 src/usr.bin/make/unit-tests/varname-empty.exp
diff -r1.1 -r1.2 src/usr.bin/make/unit-tests/varname-empty.mk

cvs diff -r1.457 -r1.458 src/usr.bin/make/var.c (expand / switch to unified diff)

--- src/usr.bin/make/var.c 2020/08/22 19:30:58 1.457
+++ src/usr.bin/make/var.c 2020/08/22 20:31:50 1.458
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: var.c,v 1.457 2020/08/22 19:30:58 sjg Exp $ */ 1/* $NetBSD: var.c,v 1.458 2020/08/22 20:31:50 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -59,34 +59,34 @@ @@ -59,34 +59,34 @@
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71#ifndef MAKE_NATIVE 71#ifndef MAKE_NATIVE
72static char rcsid[] = "$NetBSD: var.c,v 1.457 2020/08/22 19:30:58 sjg Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.458 2020/08/22 20:31:50 rillig Exp $";
73#else 73#else
74#include <sys/cdefs.h> 74#include <sys/cdefs.h>
75#ifndef lint 75#ifndef lint
76#if 0 76#if 0
77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; 77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
78#else 78#else
79__RCSID("$NetBSD: var.c,v 1.457 2020/08/22 19:30:58 sjg Exp $"); 79__RCSID("$NetBSD: var.c,v 1.458 2020/08/22 20:31:50 rillig Exp $");
80#endif 80#endif
81#endif /* not lint */ 81#endif /* not lint */
82#endif 82#endif
83 83
84/*- 84/*-
85 * var.c -- 85 * var.c --
86 * Variable-handling functions 86 * Variable-handling functions
87 * 87 *
88 * Interface: 88 * Interface:
89 * Var_Set Set the value of a variable in the given 89 * Var_Set Set the value of a variable in the given
90 * context. The variable is created if it doesn't 90 * context. The variable is created if it doesn't
91 * yet exist. 91 * yet exist.
92 * 92 *
@@ -768,44 +768,44 @@ Var_UnExport(const char *str) @@ -768,44 +768,44 @@ Var_UnExport(const char *str)
768 free(av); 768 free(av);
769 if (varnames != str) { 769 if (varnames != str) {
770 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 770 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
771 free(varnames_freeIt); 771 free(varnames_freeIt);
772 } 772 }
773 } 773 }
774} 774}
775 775
776/* See Var_Set for documentation. */ 776/* See Var_Set for documentation. */
777void 777void
778Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 778Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
779 VarSet_Flags flags) 779 VarSet_Flags flags)
780{ 780{
 781 const char *unexpanded_name = name;
781 char *name_freeIt = NULL; 782 char *name_freeIt = NULL;
782 Var *v; 783 Var *v;
783 784
784 /* 785 /*
785 * We only look for a variable in the given context since anything set 786 * We only look for a variable in the given context since anything set
786 * here will override anything in a lower context, so there's not much 787 * here will override anything in a lower context, so there's not much
787 * point in searching them all just to save a bit of memory... 788 * point in searching them all just to save a bit of memory...
788 */ 789 */
789 if (strchr(name, '$') != NULL) { 790 if (strchr(name, '$') != NULL)
790 const char *unexpanded_name = name; 
791 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES); 791 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES);
792 if (name[0] == '\0') { 792
793 VAR_DEBUG("Var_Set(\"%s\", \"%s\", ...) " 793 if (name[0] == '\0') {
794 "name expands to empty string - ignored\n", 794 VAR_DEBUG("Var_Set(\"%s\", \"%s\", ...) "
795 unexpanded_name, val); 795 "name expands to empty string - ignored\n",
796 free(name_freeIt); 796 unexpanded_name, val);
797 return; 797 free(name_freeIt);
798 } 798 return;
799 } 799 }
800 800
801 if (ctxt == VAR_GLOBAL) { 801 if (ctxt == VAR_GLOBAL) {
802 v = VarFind(name, VAR_CMD, 0); 802 v = VarFind(name, VAR_CMD, 0);
803 if (v != NULL) { 803 if (v != NULL) {
804 if (v->flags & VAR_FROM_CMD) { 804 if (v->flags & VAR_FROM_CMD) {
805 VAR_DEBUG("%s:%s = %s ignored!\n", ctxt->name, name, val); 805 VAR_DEBUG("%s:%s = %s ignored!\n", ctxt->name, name, val);
806 goto out; 806 goto out;
807 } 807 }
808 VarFreeEnv(v, TRUE); 808 VarFreeEnv(v, TRUE);
809 } 809 }
810 } 810 }
811 811

cvs diff -r1.1 -r1.2 src/usr.bin/make/unit-tests/varname-empty.exp (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/varname-empty.exp 2020/08/22 20:23:14 1.1
+++ src/usr.bin/make/unit-tests/varname-empty.exp 2020/08/22 20:31:50 1.2
@@ -1,3 +1,3 @@ @@ -1,3 +1,3 @@
1value 1fallback
2value value value 21 2 3
3exit status 0 3exit status 0

cvs diff -r1.1 -r1.2 src/usr.bin/make/unit-tests/varname-empty.mk (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/varname-empty.mk 2020/08/22 20:23:14 1.1
+++ src/usr.bin/make/unit-tests/varname-empty.mk 2020/08/22 20:31:50 1.2
@@ -1,21 +1,22 @@ @@ -1,21 +1,22 @@
1# $NetBSD: varname-empty.mk,v 1.1 2020/08/22 20:23:14 rillig Exp $ 1# $NetBSD: varname-empty.mk,v 1.2 2020/08/22 20:31:50 rillig Exp $
2# 2#
3# Tests for the special variable with the empty name. 3# Tests for the special variable with the empty name.
4# 4#
5# The variable "" is not supposed to be assigned any value. 5# The variable "" is not supposed to be assigned any value.
6# This is because it is heavily used in the .for loop expansion, 6# This is because it is heavily used in the .for loop expansion,
7# as well as to generate arbitrary strings, as in ${:Ufallback}. 7# as well as to generate arbitrary strings, as in ${:Ufallback}.
8 8
9# Oops. 9# Until 2020-08-22 it was possible to assign a value to the variable with
 10# the empty name, leading to all kinds of unexpected effects.
10!= echo 'value' 11!= echo 'value'
11 12
12# The .for loop expands the expression ${i} to ${:U1}, ${:U2} and so on. 13# The .for loop expands the expression ${i} to ${:U1}, ${:U2} and so on.
13# This only works if the variable with the empty name is guaranteed to 14# This only works if the variable with the empty name is guaranteed to
14# be undefined. 15# be undefined.
15.for i in 1 2 3 16.for i in 1 2 3
16NUMBERS+= ${i} 17NUMBERS+= ${i}
17.endfor 18.endfor
18 19
19all: 20all:
20 @echo ${:Ufallback} 21 @echo ${:Ufallback}
21 @echo ${NUMBERS} 22 @echo ${NUMBERS}