From 5de02beb666b06c2e9a909b315b78bd1e014072b Mon Sep 17 00:00:00 2001 From: rillig Date: Sun, 9 Jan 2022 14:06:00 +0000 Subject: [PATCH] make: fix crash for newline in .for value in -dp mode (since yesterday) --- usr.bin/make/for.c | 26 ++++++++++--------- .../make/unit-tests/directive-for-escape.exp | 16 ++++++++++++ .../make/unit-tests/directive-for-escape.mk | 17 +++++++++++- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/usr.bin/make/for.c b/usr.bin/make/for.c index b649e2eb07f5..786d3c507950 100644 --- a/usr.bin/make/for.c +++ b/usr.bin/make/for.c @@ -1,4 +1,4 @@ -/* $NetBSD: for.c,v 1.163 2022/01/09 12:43:52 rillig Exp $ */ +/* $NetBSD: for.c,v 1.164 2022/01/09 14:06:00 rillig Exp $ */ /* * Copyright (c) 1992, The Regents of the University of California. @@ -58,7 +58,7 @@ #include "make.h" /* "@(#)for.c 8.1 (Berkeley) 6/6/93" */ -MAKE_RCSID("$NetBSD: for.c,v 1.163 2022/01/09 12:43:52 rillig Exp $"); +MAKE_RCSID("$NetBSD: for.c,v 1.164 2022/01/09 14:06:00 rillig Exp $"); typedef struct ForLoop { @@ -367,8 +367,8 @@ AddEscaped(Buffer *cmds, Substring item, char endc) * expression like ${i} or ${i:...} or $(i) or $(i:...) with ":Uvalue". */ static void -ForLoop_SubstVarLong(ForLoop *f, Buffer *body, const char **pp, - char endc, const char **inout_mark) +ForLoop_SubstVarLong(ForLoop *f, unsigned int firstItem, Buffer *body, + const char **pp, char endc, const char **inout_mark) { size_t i; const char *start = *pp; @@ -392,7 +392,7 @@ ForLoop_SubstVarLong(ForLoop *f, Buffer *body, const char **pp, */ Buf_AddBytesBetween(body, *inout_mark, start); Buf_AddStr(body, ":U"); - AddEscaped(body, f->items.words[f->nextItem + i], endc); + AddEscaped(body, f->items.words[firstItem + i], endc); *inout_mark = p; *pp = p; @@ -405,7 +405,7 @@ ForLoop_SubstVarLong(ForLoop *f, Buffer *body, const char **pp, * variable expressions like $i with their ${:U...} expansion. */ static void -ForLoop_SubstVarShort(ForLoop *f, Buffer *body, +ForLoop_SubstVarShort(ForLoop *f, unsigned int firstItem, Buffer *body, const char *p, const char **inout_mark) { const char ch = *p; @@ -430,7 +430,7 @@ found: /* Replace $ with ${:U} */ Buf_AddStr(body, "{:U"); - AddEscaped(body, f->items.words[f->nextItem + i], '}'); + AddEscaped(body, f->items.words[firstItem + i], '}'); Buf_AddByte(body, '}'); } @@ -448,7 +448,7 @@ found: * possible to contrive a makefile where an unwanted substitution happens. */ static void -ForLoop_SubstBody(ForLoop *f, Buffer *body) +ForLoop_SubstBody(ForLoop *f, unsigned int firstItem, Buffer *body) { const char *p, *end; const char *mark; /* where the last substitution left off */ @@ -461,9 +461,11 @@ ForLoop_SubstBody(ForLoop *f, Buffer *body) if (p[1] == '{' || p[1] == '(') { char endc = p[1] == '{' ? '}' : ')'; p += 2; - ForLoop_SubstVarLong(f, body, &p, endc, &mark); + ForLoop_SubstVarLong(f, firstItem, body, + &p, endc, &mark); } else if (p[1] != '\0') { - ForLoop_SubstVarShort(f, body, p + 1, &mark); + ForLoop_SubstVarShort(f, firstItem, body, + p + 1, &mark); p += 2; } else break; @@ -482,9 +484,9 @@ For_NextIteration(ForLoop *f, Buffer *body) if (f->nextItem == f->items.len) return false; - ForLoop_SubstBody(f, body); - DEBUG1(FOR, "For: loop body:\n%s", body->data); f->nextItem += (unsigned int)f->vars.len; + ForLoop_SubstBody(f, f->nextItem - (unsigned int)f->vars.len, body); + DEBUG1(FOR, "For: loop body:\n%s", body->data); return true; } diff --git a/usr.bin/make/unit-tests/directive-for-escape.exp b/usr.bin/make/unit-tests/directive-for-escape.exp index 492f82e16d1f..777feb512f87 100644 --- a/usr.bin/make/unit-tests/directive-for-escape.exp +++ b/usr.bin/make/unit-tests/directive-for-escape.exp @@ -87,6 +87,22 @@ For: loop body: . info long: ${:U" "} make: "directive-for-escape.mk" line 138: short: " " make: "directive-for-escape.mk" line 139: long: " " +For: end for 1 +For: loop body: +For: end for 1 +Parse_PushInput: .for loop in directive-for-escape.mk, line 152 +make: "directive-for-escape.mk" line 152: newline in .for value + in .for loop from directive-for-escape.mk:152 with i = " +" +For: loop body: +: ${:U" "} +SetFilenameVars: ${.PARSEDIR} = `' ${.PARSEFILE} = `directive-for-escape.mk' +Parsing line 153: : ${:U" "} +ParseDependency(: " ") +ParseEOF: returning to file directive-for-escape.mk, line 155 +SetFilenameVars: ${.PARSEDIR} = `' ${.PARSEFILE} = `directive-for-escape.mk' +Parsing line 155: .MAKEFLAGS: -d0 +ParseDependency(.MAKEFLAGS: -d0) make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/usr.bin/make/unit-tests/directive-for-escape.mk b/usr.bin/make/unit-tests/directive-for-escape.mk index 725fa85d68c3..5dfdc6d9b835 100644 --- a/usr.bin/make/unit-tests/directive-for-escape.mk +++ b/usr.bin/make/unit-tests/directive-for-escape.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-for-escape.mk,v 1.12 2021/12/05 11:40:03 rillig Exp $ +# $NetBSD: directive-for-escape.mk,v 1.13 2022/01/09 14:06:00 rillig Exp $ # # Test escaping of special characters in the iteration values of a .for loop. # These values get expanded later using the :U variable modifier, and this @@ -139,4 +139,19 @@ ${closing-brace}= # alternative interpretation . info long: ${i} .endfor +# No error since the newline character is not actually used. +.for i in "${.newline}" +.endfor + +# Between for.c 1.161 from 2022-01-08 and before for.c 1.163 from 2022-01-09, +# a newline character in a .for loop led to a crash since at the point where +# the error message including the stack trace is printed, the body of the .for +# loop is assembled, and at that point, ForLoop.nextItem had already been +# advanced. +.MAKEFLAGS: -dp +.for i in "${.newline}" +: $i +.endfor +.MAKEFLAGS: -d0 + all: