Module Name:    src
Committed By:   rillig
Date:           Sat Jun 15 22:06:31 UTC 2024

Modified Files:
        src/usr.bin/make: var.c
        src/usr.bin/make/unit-tests: varname-dot-newline.exp
            varname-dot-newline.mk

Log Message:
make: error out if an internal read-only variable is overwritten

The affected variables are:
* .newline
* .MAKE.OS
* .MAKE.JOBS.C
* .MAKE.LEVEL.ENV
* .MAKE.PID
* .MAKE.PPID
* .MAKE.UID
* .MAKE.GID

This change does not affect the .SHELL and .SUFFIXES variables, as well
as variables that are manually turned read-only by the special .READONLY
target.


To generate a diff of this commit:
cvs rdiff -u -r1.1120 -r1.1121 src/usr.bin/make/var.c
cvs rdiff -u -r1.4 -r1.5 src/usr.bin/make/unit-tests/varname-dot-newline.exp
cvs rdiff -u -r1.6 -r1.7 src/usr.bin/make/unit-tests/varname-dot-newline.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.1120 src/usr.bin/make/var.c:1.1121
--- src/usr.bin/make/var.c:1.1120	Sat Jun 15 20:02:45 2024
+++ src/usr.bin/make/var.c	Sat Jun 15 22:06:30 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.1120 2024/06/15 20:02:45 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.1121 2024/06/15 22:06:30 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -132,7 +132,7 @@
 #include "metachar.h"
 
 /*	"@(#)var.c	8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.1120 2024/06/15 20:02:45 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1121 2024/06/15 22:06:30 rillig Exp $");
 
 /*
  * Variables are defined using one of the VAR=value assignments.  Their
@@ -192,6 +192,12 @@ typedef struct Var {
 	bool readOnly:1;
 
 	/*
+	 * The variable is read-only and immune to the .NOREADONLY special
+	 * target.  Any attempt to modify it results in an error.
+	 */
+	bool readOnlyLoud:1;
+
+	/*
 	 * The variable is currently being accessed by Var_Parse or Var_Subst.
 	 * This temporary marker is used to avoid endless recursion.
 	 */
@@ -393,6 +399,7 @@ VarNew(FStr name, const char *value,
 	var->shortLived = shortLived;
 	var->fromEnvironment = fromEnvironment;
 	var->readOnly = readOnly;
+	var->readOnlyLoud = false;
 	var->inUse = false;
 	var->exported = false;
 	var->reexport = false;
@@ -552,6 +559,12 @@ Var_Delete(GNode *scope, const char *var
 	}
 
 	v = he->value;
+	if (v->readOnlyLoud) {
+		Parse_Error(PARSE_FATAL,
+		    "Cannot delete \"%s\" as it is read-only",
+		    v->name.str);
+		return;
+	}
 	if (v->readOnly) {
 		DEBUG2(VAR, "%s: ignoring delete '%s' as it is read-only\n",
 		    scope->name, varname);
@@ -1025,6 +1038,12 @@ Var_SetWithFlags(GNode *scope, const cha
 		}
 		v = VarAdd(name, val, scope, flags);
 	} else {
+		if (v->readOnlyLoud) {
+			Parse_Error(PARSE_FATAL,
+			    "Cannot overwrite \"%s\" as it is read-only",
+			    name);
+			return;
+		}
 		if (v->readOnly && !(flags & VAR_SET_READONLY)) {
 			DEBUG3(VAR,
 			    "%s: ignoring '%s = %s' as it is read-only\n",
@@ -1117,7 +1136,8 @@ Global_Delete(const char *name)
 void
 Global_Set_ReadOnly(const char *name, const char *value)
 {
-	Var_SetWithFlags(SCOPE_GLOBAL, name, value, VAR_SET_READONLY);
+	Var_SetWithFlags(SCOPE_GLOBAL, name, value, VAR_SET_NONE);
+	VarFind(name, SCOPE_GLOBAL, false)->readOnlyLoud = true;
 }
 
 /*
@@ -1135,6 +1155,10 @@ Var_Append(GNode *scope, const char *nam
 
 	if (v == NULL) {
 		Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
+	} else if (v->readOnlyLoud) {
+		Parse_Error(PARSE_FATAL,
+		    "Cannot append to \"%s\" as it is read-only", name);
+		return;
 	} else if (v->readOnly) {
 		DEBUG3(VAR, "%s: ignoring '%s += %s' as it is read-only\n",
 		    scope->name, name, val);

Index: src/usr.bin/make/unit-tests/varname-dot-newline.exp
diff -u src/usr.bin/make/unit-tests/varname-dot-newline.exp:1.4 src/usr.bin/make/unit-tests/varname-dot-newline.exp:1.5
--- src/usr.bin/make/unit-tests/varname-dot-newline.exp:1.4	Thu Jan 26 20:48:18 2023
+++ src/usr.bin/make/unit-tests/varname-dot-newline.exp	Sat Jun 15 22:06:31 2024
@@ -1,3 +1,8 @@
+make: "varname-dot-newline.mk" line 28: Cannot overwrite ".newline" as it is read-only
+make: "varname-dot-newline.mk" line 30: Cannot append to ".newline" as it is read-only
+make: "varname-dot-newline.mk" line 32: Cannot delete ".newline" as it is read-only
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
 first
 second
 backslash newline: <\

Index: src/usr.bin/make/unit-tests/varname-dot-newline.mk
diff -u src/usr.bin/make/unit-tests/varname-dot-newline.mk:1.6 src/usr.bin/make/unit-tests/varname-dot-newline.mk:1.7
--- src/usr.bin/make/unit-tests/varname-dot-newline.mk:1.6	Thu Jan 26 20:48:18 2023
+++ src/usr.bin/make/unit-tests/varname-dot-newline.mk	Sat Jun 15 22:06:31 2024
@@ -1,4 +1,4 @@
-# $NetBSD: varname-dot-newline.mk,v 1.6 2023/01/26 20:48:18 sjg Exp $
+# $NetBSD: varname-dot-newline.mk,v 1.7 2024/06/15 22:06:31 rillig Exp $
 #
 # Tests for the special .newline variable, which contains a single newline
 # character (U+000A).
@@ -20,12 +20,23 @@ BACKSLASH_NEWLINE:=	\${.newline}
 
 NEWLINE:=	${.newline}
 
+.if make(try-to-modify)
+# A '?=' assignment is fine.  This pattern can be used to provide the variable
+# to older or other variants of make that don't know that variable.
+.newline?=	fallback
+# expect+1: Cannot overwrite ".newline" as it is read-only
 .newline=	overwritten
+# expect+1: Cannot append to ".newline" as it is read-only
+.newline+=	appended
+# expect+1: Cannot delete ".newline" as it is read-only
+.undef .newline
+.endif
 
 .if ${.newline} != ${NEWLINE}
 .  error The .newline variable can be overwritten.  It should be read-only.
 .endif
 
 all:
+	@${MAKE} -f ${MAKEFILE} try-to-modify || true
 	@echo 'first${.newline}second'
 	@echo 'backslash newline: <${BACKSLASH_NEWLINE}>'

Reply via email to