1*d5e0a182SSimon J. Gerraty# $NetBSD: varname-empty.mk,v 1.10 2023/11/19 21:47:52 rillig Exp $ 22c3632d1SSimon J. Gerraty# 32c3632d1SSimon J. Gerraty# Tests for the special variable with the empty name. 42c3632d1SSimon J. Gerraty# 5956e45f6SSimon J. Gerraty# There is no variable named "" at all, and this fact is used a lot in 6*d5e0a182SSimon J. Gerraty# expressions of the form ${:Ufallback}. These expressions are 7956e45f6SSimon J. Gerraty# based on the variable named "" and use the :U modifier to assign a 8956e45f6SSimon J. Gerraty# fallback value to the expression (but not to the variable). 9956e45f6SSimon J. Gerraty# 10956e45f6SSimon J. Gerraty# This form of expressions is used to implement value substitution in the 11956e45f6SSimon J. Gerraty# .for loops. Another use case is in a variable assignment of the form 12956e45f6SSimon J. Gerraty# ${:Uvarname}=value, which allows for characters in the variable name that 13956e45f6SSimon J. Gerraty# would otherwise be interpreted by the parser, such as whitespace, ':', 14956e45f6SSimon J. Gerraty# '=', '$', backslash. 15956e45f6SSimon J. Gerraty# 16956e45f6SSimon J. Gerraty# The only places where a variable is assigned a value are Var_Set and 17956e45f6SSimon J. Gerraty# Var_Append, and these places protect the variable named "" from being 18956e45f6SSimon J. Gerraty# defined. This is different from read-only variables, as that flag can 19956e45f6SSimon J. Gerraty# only apply to variables that are defined. The variable named "" must 20956e45f6SSimon J. Gerraty# never be defined though. 21956e45f6SSimon J. Gerraty# 22956e45f6SSimon J. Gerraty# See also: 23956e45f6SSimon J. Gerraty# The special variables @F or ^D, in var-class-local.mk 242c3632d1SSimon J. Gerraty 252c3632d1SSimon J. Gerraty# Until 2020-08-22 it was possible to assign a value to the variable with 26956e45f6SSimon J. Gerraty# the empty name, leading to all kinds of unexpected effects in .for loops 27956e45f6SSimon J. Gerraty# and other places that assume that ${:Ufallback} expands to "fallback". 28956e45f6SSimon J. Gerraty# The bug in Var_Set was that only expanded variables had been checked for 29956e45f6SSimon J. Gerraty# the empty name, but not the direct assignments with an empty name. 302c3632d1SSimon J. Gerraty?= default 312c3632d1SSimon J. Gerraty= assigned # undefined behavior until 2020-08-22 322c3632d1SSimon J. Gerraty+= appended 332c3632d1SSimon J. Gerraty:= subst 342c3632d1SSimon J. Gerraty!= echo 'shell-output' 35956e45f6SSimon J. Gerraty.if ${:Ufallback} != "fallback" 36956e45f6SSimon J. Gerraty. error 37956e45f6SSimon J. Gerraty.endif 38956e45f6SSimon J. Gerraty 39956e45f6SSimon J. Gerraty${:U}= assigned indirectly 40956e45f6SSimon J. Gerraty.if ${:Ufallback} != "fallback" 41956e45f6SSimon J. Gerraty. error 42956e45f6SSimon J. Gerraty.endif 43956e45f6SSimon J. Gerraty 44dba7b0efSSimon J. Gerraty${:U}+= appended indirectly 45dba7b0efSSimon J. Gerraty.if ${:Ufallback} != "fallback" 46dba7b0efSSimon J. Gerraty. error 47dba7b0efSSimon J. Gerraty.endif 48dba7b0efSSimon J. Gerraty 49dba7b0efSSimon J. Gerraty.MAKEFLAGS: -d0 50dba7b0efSSimon J. Gerraty 51956e45f6SSimon J. Gerraty# Before 2020-08-22, the simple assignment operator '=' after an empty 52b0c40a00SSimon J. Gerraty# variable name had an off-by-one bug in Parse_Var. The code that was 53956e45f6SSimon J. Gerraty# supposed to "skip to operator character" started its search _after_ the 54956e45f6SSimon J. Gerraty# assignment operator, assuming that the variable name would be at least 55956e45f6SSimon J. Gerraty# one character long. It then looked for the next occurrence of a '=', which 56956e45f6SSimon J. Gerraty# could be several lines away or not occur at all. While looking for the 57956e45f6SSimon J. Gerraty# '=', some whitespace was nulled out, leading to out-of-bounds write. 58956e45f6SSimon J. Gerraty= assigned # undefined behavior until 2020-08-22 592c3632d1SSimon J. Gerraty 602c3632d1SSimon J. Gerraty# The .for loop expands the expression ${i} to ${:U1}, ${:U2} and so on. 612c3632d1SSimon J. Gerraty# This only works if the variable with the empty name is guaranteed to 622c3632d1SSimon J. Gerraty# be undefined. 632c3632d1SSimon J. Gerraty.for i in 1 2 3 642c3632d1SSimon J. GerratyNUMBERS+= ${i} 652c3632d1SSimon J. Gerraty.endfor 662c3632d1SSimon J. Gerraty 672c3632d1SSimon J. Gerratyall: 682c3632d1SSimon J. Gerraty @echo out: ${:Ufallback} 692c3632d1SSimon J. Gerraty @echo out: ${NUMBERS} 70