Wed Jul 29 20:33:38 2020 UTC ()
make(1): fix segfault when evaluating ${::=value}

The bug had been in the handling of the SysV modifier for many years, but
it had not been triggered since the "parsing position for the next
modifier" had been initialized to a non-NULL pointer.

In var.v r1.350, this pointer had been initialized to NULL instead since
every ApplyModifier function must set it in every case where it returns
anything except "default_case".

There might have been a slight chance of tricking make to output a wrong
error message, but nothing worse.


(rillig)
diff -r1.354 -r1.355 src/usr.bin/make/var.c
diff -r1.8 -r1.9 src/usr.bin/make/unit-tests/moderrs.exp
diff -r1.7 -r1.8 src/usr.bin/make/unit-tests/moderrs.mk

cvs diff -r1.354 -r1.355 src/usr.bin/make/var.c (expand / switch to unified diff)

--- src/usr.bin/make/var.c 2020/07/29 19:48:33 1.354
+++ src/usr.bin/make/var.c 2020/07/29 20:33:38 1.355
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: var.c,v 1.354 2020/07/29 19:48:33 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -59,34 +59,34 @@ @@ -59,34 +59,34 @@
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71#ifndef MAKE_NATIVE 71#ifndef MAKE_NATIVE
72static char rcsid[] = "$NetBSD: var.c,v 1.354 2020/07/29 19:48:33 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $";
73#else 73#else
74#include <sys/cdefs.h> 74#include <sys/cdefs.h>
75#ifndef lint 75#ifndef lint
76#if 0 76#if 0
77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; 77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
78#else 78#else
79__RCSID("$NetBSD: var.c,v 1.354 2020/07/29 19:48:33 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $");
80#endif 80#endif
81#endif /* not lint */ 81#endif /* not lint */
82#endif 82#endif
83 83
84/*- 84/*-
85 * var.c -- 85 * var.c --
86 * Variable-handling functions 86 * Variable-handling functions
87 * 87 *
88 * Interface: 88 * Interface:
89 * Var_Set Set the value of a variable in the given 89 * Var_Set Set the value of a variable in the given
90 * context. The variable is created if it doesn't 90 * context. The variable is created if it doesn't
91 * yet exist. 91 * yet exist.
92 * 92 *
@@ -2565,27 +2565,27 @@ ApplyModifier_ToSep(const char *sep, App @@ -2565,27 +2565,27 @@ ApplyModifier_ToSep(const char *sep, App
2565 } else { 2565 } else {
2566 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ 2566 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */
2567 } 2567 }
2568 2568
2569 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2569 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2570 ModifyWord_Copy, NULL); 2570 ModifyWord_Copy, NULL);
2571 return TRUE; 2571 return TRUE;
2572} 2572}
2573 2573
2574/* :tA, :tu, :tl, :ts<separator>, etc. */ 2574/* :tA, :tu, :tl, :ts<separator>, etc. */
2575static Boolean 2575static Boolean
2576ApplyModifier_To(const char *mod, ApplyModifiersState *st) 2576ApplyModifier_To(const char *mod, ApplyModifiersState *st)
2577{ 2577{
2578 st->next = mod + 1; /* make sure it is set */ 2578 st->next = mod + 1; /* make sure it is set */
2579 if (mod[1] == st->endc || mod[1] == ':') 2579 if (mod[1] == st->endc || mod[1] == ':')
2580 return FALSE; /* Found ":t<endc>" or ":t:". */ 2580 return FALSE; /* Found ":t<endc>" or ":t:". */
2581 2581
2582 if (mod[1] == 's') 2582 if (mod[1] == 's')
2583 return ApplyModifier_ToSep(mod + 2, st); 2583 return ApplyModifier_ToSep(mod + 2, st);
2584 2584
2585 if (mod[2] != st->endc && mod[2] != ':') 2585 if (mod[2] != st->endc && mod[2] != ':')
2586 return FALSE; /* Found ":t<unrecognised><unrecognised>". */ 2586 return FALSE; /* Found ":t<unrecognised><unrecognised>". */
2587 2587
2588 /* Check for two-character options: ":tu", ":tl" */ 2588 /* Check for two-character options: ":tu", ":tl" */
2589 if (mod[1] == 'A') { /* absolute path */ 2589 if (mod[1] == 'A') { /* absolute path */
2590 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2590 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2591 ModifyWord_Realpath, NULL); 2591 ModifyWord_Realpath, NULL);
@@ -2808,28 +2808,30 @@ ApplyModifier_IfElse(const char *mod, Ap @@ -2808,28 +2808,30 @@ ApplyModifier_IfElse(const char *mod, Ap
2808 * variable. 2808 * variable.
2809 */ 2809 */
2810static int 2810static int
2811ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) 2811ApplyModifier_Assign(const char *mod, ApplyModifiersState *st)
2812{ 2812{
2813 const char *op = mod + 1; 2813 const char *op = mod + 1;
2814 if (!(op[0] == '=' || 2814 if (!(op[0] == '=' ||
2815 (op[1] == '=' && 2815 (op[1] == '=' &&
2816 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2816 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2817 return 'd'; /* "::<unrecognised>" */ 2817 return 'd'; /* "::<unrecognised>" */
2818 2818
2819 GNode *v_ctxt; /* context where v belongs */ 2819 GNode *v_ctxt; /* context where v belongs */
2820 2820
2821 if (st->v->name[0] == 0) 2821 if (st->v->name[0] == 0) {
 2822 st->next = mod + 1;
2822 return 'b'; 2823 return 'b';
 2824 }
2823 2825
2824 v_ctxt = st->ctxt; 2826 v_ctxt = st->ctxt;
2825 char *sv_name = NULL; 2827 char *sv_name = NULL;
2826 if (st->v->flags & VAR_JUNK) { 2828 if (st->v->flags & VAR_JUNK) {
2827 /* 2829 /*
2828 * We need to bmake_strdup() it incase ParseModifierPart() recurses. 2830 * We need to bmake_strdup() it incase ParseModifierPart() recurses.
2829 */ 2831 */
2830 sv_name = st->v->name; 2832 sv_name = st->v->name;
2831 st->v->name = bmake_strdup(st->v->name); 2833 st->v->name = bmake_strdup(st->v->name);
2832 } else if (st->ctxt != VAR_GLOBAL) { 2834 } else if (st->ctxt != VAR_GLOBAL) {
2833 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2835 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2834 if (gv == NULL) 2836 if (gv == NULL)
2835 v_ctxt = VAR_GLOBAL; 2837 v_ctxt = VAR_GLOBAL;
@@ -3107,26 +3109,27 @@ ApplyModifiers(char *val, const char * c @@ -3107,26 +3109,27 @@ ApplyModifiers(char *val, const char * c
3107 Error("Unclosed variable specification after complex " 3109 Error("Unclosed variable specification after complex "
3108 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3110 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3109 goto out; 3111 goto out;
3110 } 3112 }
3111 continue; 3113 continue;
3112 } 3114 }
3113 apply_mods: 3115 apply_mods:
3114 if (DEBUG(VAR)) { 3116 if (DEBUG(VAR)) {
3115 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, 3117 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3116 *p, st.val); 3118 *p, st.val);
3117 } 3119 }
3118 st.newVal = var_Error; 3120 st.newVal = var_Error;
3119 char modifier = *p; 3121 char modifier = *p;
 3122 st.next = NULL; /* fail fast if an ApplyModifier forgets to set this */
3120 switch (modifier) { 3123 switch (modifier) {
3121 case ':': 3124 case ':':
3122 { 3125 {
3123 int res = ApplyModifier_Assign(p, &st); 3126 int res = ApplyModifier_Assign(p, &st);
3124 if (res == 'b') 3127 if (res == 'b')
3125 goto bad_modifier; 3128 goto bad_modifier;
3126 if (res == 'c') 3129 if (res == 'c')
3127 goto cleanup; 3130 goto cleanup;
3128 if (res == 'd') 3131 if (res == 'd')
3129 goto default_case; 3132 goto default_case;
3130 break; 3133 break;
3131 } 3134 }
3132 case '@': 3135 case '@':

cvs diff -r1.8 -r1.9 src/usr.bin/make/unit-tests/moderrs.exp (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/moderrs.exp 2020/07/29 19:48:33 1.8
+++ src/usr.bin/make/unit-tests/moderrs.exp 2020/07/29 20:33:38 1.9
@@ -107,26 +107,28 @@ M*} @@ -107,26 +107,28 @@ M*}
107mod-ifelse-parse: 107mod-ifelse-parse:
108make: Unclosed substitution for FIB (: missing) 108make: Unclosed substitution for FIB (: missing)
109 109
110make: Unclosed substitution for FIB (: missing) 110make: Unclosed substitution for FIB (: missing)
111 111
112make: Unclosed substitution for FIB (} missing) 112make: Unclosed substitution for FIB (} missing)
113 113
114make: Unclosed substitution for FIB (} missing) 114make: Unclosed substitution for FIB (} missing)
115 115
116then 116then
117mod-assign-parse: 117mod-assign-parse:
118make: Unknown modifier ':' 118make: Unknown modifier ':'
119 119
 120make: Bad modifier `:' for
 121value}
120make: Unclosed substitution for ASSIGN (} missing) 122make: Unclosed substitution for ASSIGN (} missing)
121 123
122mod-remember-parse: 124mod-remember-parse:
1231 1 2 3 5 8 13 21 34 1251 1 2 3 5 8 13 21 34
124make: Unknown modifier '_' 126make: Unknown modifier '_'
125 127
126mod-sysv-parse: 128mod-sysv-parse:
127make: Unknown modifier '3' 129make: Unknown modifier '3'
128make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3 130make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3
129 131
130make: Unknown modifier '3' 132make: Unknown modifier '3'
131make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3 133make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3
132 134

cvs diff -r1.7 -r1.8 src/usr.bin/make/unit-tests/moderrs.mk (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/moderrs.mk 2020/07/29 19:48:33 1.7
+++ src/usr.bin/make/unit-tests/moderrs.mk 2020/07/29 20:33:38 1.8
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $Id: moderrs.mk,v 1.7 2020/07/29 19:48:33 rillig Exp $ 1# $Id: moderrs.mk,v 1.8 2020/07/29 20:33:38 rillig Exp $
2# 2#
3# various modifier error tests 3# various modifier error tests
4 4
5VAR=TheVariable 5VAR=TheVariable
6# incase we have to change it ;-) 6# incase we have to change it ;-)
7MOD_UNKN=Z 7MOD_UNKN=Z
8MOD_TERM=S,V,v 8MOD_TERM=S,V,v
9MOD_S:= ${MOD_TERM}, 9MOD_S:= ${MOD_TERM},
10 10
11FIB= 1 1 2 3 5 8 13 21 34 11FIB= 1 1 2 3 5 8 13 21 34
12 12
13all: modunkn modunknV varterm vartermV modtermV modloop 13all: modunkn modunknV varterm vartermV modtermV modloop
14all: modloop-close 14all: modloop-close
@@ -141,29 +141,27 @@ mod-t-parse: @@ -141,29 +141,27 @@ mod-t-parse:
141 @echo ${FIB:t:M*} 141 @echo ${FIB:t:M*}
142 142
143mod-ifelse-parse: 143mod-ifelse-parse:
144 @echo $@: 144 @echo $@:
145 @echo ${FIB:? 145 @echo ${FIB:?
146 @echo ${FIB:?then 146 @echo ${FIB:?then
147 @echo ${FIB:?then: 147 @echo ${FIB:?then:
148 @echo ${FIB:?then:else 148 @echo ${FIB:?then:else
149 @echo ${FIB:?then:else} 149 @echo ${FIB:?then:else}
150 150
151mod-assign-parse: 151mod-assign-parse:
152 @echo $@: 152 @echo $@:
153 @echo ${ASSIGN::x} # 'x' is an unknown assignment operator 153 @echo ${ASSIGN::x} # 'x' is an unknown assignment operator
154# disabled for now; segfaults on NetBSD-8.0-x86_64 in Var_Parse line 3636: 154 @echo ${::=value} # trying to set the empty variable
155# *lengthPtr = tstr - str + (*tstr ? 1 : 0); 
156# @echo ${::=value} # trying to set the empty variable 
157 @echo ${ASSIGN::=value # missing closing brace 155 @echo ${ASSIGN::=value # missing closing brace
158 156
159mod-remember-parse: 157mod-remember-parse:
160 @echo $@: 158 @echo $@:
161 @echo ${FIB:_} # ok 159 @echo ${FIB:_} # ok
162 @echo ${FIB:__} # modifier name too long 160 @echo ${FIB:__} # modifier name too long
163 161
164mod-sysv-parse: 162mod-sysv-parse:
165 @echo $@: 163 @echo $@:
166 @echo ${FIB:3 164 @echo ${FIB:3
167 @echo ${FIB:3= 165 @echo ${FIB:3=
168 @echo ${FIB:3=x3 166 @echo ${FIB:3=x3
169 @echo ${FIB:3=x3} # ok 167 @echo ${FIB:3=x3} # ok