aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests/varmod-loop-delete.mk
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bmake/unit-tests/varmod-loop-delete.mk')
-rw-r--r--contrib/bmake/unit-tests/varmod-loop-delete.mk34
1 files changed, 34 insertions, 0 deletions
diff --git a/contrib/bmake/unit-tests/varmod-loop-delete.mk b/contrib/bmake/unit-tests/varmod-loop-delete.mk
new file mode 100644
index 000000000000..1ec6d361949d
--- /dev/null
+++ b/contrib/bmake/unit-tests/varmod-loop-delete.mk
@@ -0,0 +1,34 @@
+# $NetBSD: varmod-loop-delete.mk,v 1.3 2023/06/01 20:56:35 rillig Exp $
+#
+# Tests for the variable modifier ':@', which as a side effect allows to
+# delete an arbitrary variable.
+
+# A side effect of the modifier ':@' is that the loop variable is created as
+# an actual variable in the current evaluation scope (Command/Global/target),
+# and at the end of the loop, this variable is deleted. Since var.c 1.204
+# from 2016-02-18 and before var.c 1.963 from 2021-12-05, a variable could be
+# deleted while it was in use, leading to a use-after-free bug.
+#
+# See Var_Parse, comment 'the value of the variable must not change'.
+
+# Set up the variable that deletes itself when it is evaluated.
+VAR= ${:U:@VAR@@} rest of the value
+
+# In an assignment, the scope is 'Global'. Since the variable 'VAR' is
+# defined in the global scope, it deletes itself.
+# expect+1: Cannot delete variable "VAR" while it is used
+EVAL:= ${VAR}
+.if ${EVAL} != " rest of the value"
+. error
+.endif
+
+VAR= ${:U:@VAR@@} rest of the value
+all: .PHONY
+ # In the command that is associated with a target, the scope is the
+ # one from the target. That scope only contains a few variables like
+ # '.TARGET', '.ALLSRC', '.IMPSRC'. Make does not expect that these
+ # variables get modified from the outside.
+ #
+ # There is no variable named 'VAR' in the local scope, so nothing
+ # happens.
+ : $@: '${VAR}'