1# $NetBSD: varname-empty.mk,v 1.9 2021/04/04 10:13:09 rillig Exp $ 2# 3# Tests for the special variable with the empty name. 4# 5# There is no variable named "" at all, and this fact is used a lot in 6# variable expressions of the form ${:Ufallback}. These expressions are 7# based on the variable named "" and use the :U modifier to assign a 8# fallback value to the expression (but not to the variable). 9# 10# This form of expressions is used to implement value substitution in the 11# .for loops. Another use case is in a variable assignment of the form 12# ${:Uvarname}=value, which allows for characters in the variable name that 13# would otherwise be interpreted by the parser, such as whitespace, ':', 14# '=', '$', backslash. 15# 16# The only places where a variable is assigned a value are Var_Set and 17# Var_Append, and these places protect the variable named "" from being 18# defined. This is different from read-only variables, as that flag can 19# only apply to variables that are defined. The variable named "" must 20# never be defined though. 21# 22# See also: 23# The special variables @F or ^D, in var-class-local.mk 24 25# Until 2020-08-22 it was possible to assign a value to the variable with 26# the empty name, leading to all kinds of unexpected effects in .for loops 27# and other places that assume that ${:Ufallback} expands to "fallback". 28# The bug in Var_Set was that only expanded variables had been checked for 29# the empty name, but not the direct assignments with an empty name. 30?= default 31= assigned # undefined behavior until 2020-08-22 32+= appended 33:= subst 34!= echo 'shell-output' 35.if ${:Ufallback} != "fallback" 36. error 37.endif 38 39${:U}= assigned indirectly 40.if ${:Ufallback} != "fallback" 41. error 42.endif 43 44${:U}+= appended indirectly 45.if ${:Ufallback} != "fallback" 46. error 47.endif 48 49.MAKEFLAGS: -d0 50 51# Before 2020-08-22, the simple assignment operator '=' after an empty 52# variable name had an off-by-one bug in Parse_Var. The code that was 53# supposed to "skip to operator character" started its search _after_ the 54# assignment operator, assuming that the variable name would be at least 55# one character long. It then looked for the next occurrence of a '=', which 56# could be several lines away or not occur at all. While looking for the 57# '=', some whitespace was nulled out, leading to out-of-bounds write. 58= assigned # undefined behavior until 2020-08-22 59 60# The .for loop expands the expression ${i} to ${:U1}, ${:U2} and so on. 61# This only works if the variable with the empty name is guaranteed to 62# be undefined. 63.for i in 1 2 3 64NUMBERS+= ${i} 65.endfor 66 67all: 68 @echo out: ${:Ufallback} 69 @echo out: ${NUMBERS} 70