aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests/varname-empty.mk
blob: fd9aa05b6057d604a1180c5b4a745b012c3b9e03 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# $NetBSD: varname-empty.mk,v 1.7 2020/10/23 17:53:01 rillig Exp $
#
# Tests for the special variable with the empty name.
#
# There is no variable named "" at all, and this fact is used a lot in
# variable expressions of the form ${:Ufallback}.  These expressions are
# based on the variable named "" and use the :U modifier to assign a
# fallback value to the expression (but not to the variable).
#
# This form of expressions is used to implement value substitution in the
# .for loops.  Another use case is in a variable assignment of the form
# ${:Uvarname}=value, which allows for characters in the variable name that
# would otherwise be interpreted by the parser, such as whitespace, ':',
# '=', '$', backslash.
#
# The only places where a variable is assigned a value are Var_Set and
# Var_Append, and these places protect the variable named "" from being
# defined.  This is different from read-only variables, as that flag can
# only apply to variables that are defined.  The variable named "" must
# never be defined though.
#
# See also:
#	The special variables @F or ^D, in var-class-local.mk

# Until 2020-08-22 it was possible to assign a value to the variable with
# the empty name, leading to all kinds of unexpected effects in .for loops
# and other places that assume that ${:Ufallback} expands to "fallback".
# The bug in Var_Set was that only expanded variables had been checked for
# the empty name, but not the direct assignments with an empty name.
?=	default
=	assigned	# undefined behavior until 2020-08-22
+=	appended
:=	subst
!=	echo 'shell-output'
.if ${:Ufallback} != "fallback"
.  error
.endif

${:U}=	assigned indirectly
.if ${:Ufallback} != "fallback"
.  error
.endif

# Before 2020-08-22, the simple assignment operator '=' after an empty
# variable name had an off-by-one bug in Parse_DoVar.  The code that was
# supposed to "skip to operator character" started its search _after_ the
# assignment operator, assuming that the variable name would be at least
# one character long.  It then looked for the next occurrence of a '=', which
# could be several lines away or not occur at all.  While looking for the
# '=', some whitespace was nulled out, leading to out-of-bounds write.
=	assigned	# undefined behavior until 2020-08-22

# The .for loop expands the expression ${i} to ${:U1}, ${:U2} and so on.
# This only works if the variable with the empty name is guaranteed to
# be undefined.
.for i in 1 2 3
NUMBERS+=	${i}
.endfor

all:
	@echo out: ${:Ufallback}
	@echo out: ${NUMBERS}