make: fix wrong expression evaluation in -dL mode The modifier ':C' now only compiles the regular expression if the result of the expression is actually needed. Several other modifiers have the same bug of evaluating the expression in cases where this is not needed. It just doesn't show up because they don't have any noticeable side effects, other than wasting CPU time. This affects irrelevant conditions as well.diff -r1.855 -r1.856 src/usr.bin/make/var.c
(rillig)
--- src/usr.bin/make/var.c 2021/02/23 16:29:52 1.855
+++ src/usr.bin/make/var.c 2021/03/14 10:57:12 1.856
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: var.c,v 1.855 2021/02/23 16:29:52 rillig Exp $ */ | 1 | /* $NetBSD: var.c,v 1.856 2021/03/14 10:57:12 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. | |
@@ -130,27 +130,27 @@ | @@ -130,27 +130,27 @@ | |||
130 | #include <regex.h> | 130 | #include <regex.h> | |
131 | #endif | 131 | #endif | |
132 | #include <errno.h> | 132 | #include <errno.h> | |
133 | #include <inttypes.h> | 133 | #include <inttypes.h> | |
134 | #include <limits.h> | 134 | #include <limits.h> | |
135 | #include <time.h> | 135 | #include <time.h> | |
136 | 136 | |||
137 | #include "make.h" | 137 | #include "make.h" | |
138 | #include "dir.h" | 138 | #include "dir.h" | |
139 | #include "job.h" | 139 | #include "job.h" | |
140 | #include "metachar.h" | 140 | #include "metachar.h" | |
141 | 141 | |||
142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | 142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | |
143 | MAKE_RCSID("$NetBSD: var.c,v 1.855 2021/02/23 16:29:52 rillig Exp $"); | 143 | MAKE_RCSID("$NetBSD: var.c,v 1.856 2021/03/14 10:57:12 rillig Exp $"); | |
144 | 144 | |||
145 | typedef enum VarFlags { | 145 | typedef enum VarFlags { | |
146 | VFL_NONE = 0, | 146 | VFL_NONE = 0, | |
147 | 147 | |||
148 | /* | 148 | /* | |
149 | * The variable's value is currently being used by Var_Parse or | 149 | * The variable's value is currently being used by Var_Parse or | |
150 | * Var_Subst. This marker is used to avoid endless recursion. | 150 | * Var_Subst. This marker is used to avoid endless recursion. | |
151 | */ | 151 | */ | |
152 | VFL_IN_USE = 1 << 0, | 152 | VFL_IN_USE = 1 << 0, | |
153 | 153 | |||
154 | /* | 154 | /* | |
155 | * The variable comes from the environment. | 155 | * The variable comes from the environment. | |
156 | * These variables are not registered in any GNode, therefore they | 156 | * These variables are not registered in any GNode, therefore they | |
@@ -2882,26 +2882,32 @@ ApplyModifier_Regex(const char **pp, App | @@ -2882,26 +2882,32 @@ ApplyModifier_Regex(const char **pp, App | |||
2882 | args.matched = FALSE; | 2882 | args.matched = FALSE; | |
2883 | oneBigWord = st->oneBigWord; | 2883 | oneBigWord = st->oneBigWord; | |
2884 | for (;; (*pp)++) { | 2884 | for (;; (*pp)++) { | |
2885 | if (**pp == 'g') | 2885 | if (**pp == 'g') | |
2886 | args.pflags.subGlobal = TRUE; | 2886 | args.pflags.subGlobal = TRUE; | |
2887 | else if (**pp == '1') | 2887 | else if (**pp == '1') | |
2888 | args.pflags.subOnce = TRUE; | 2888 | args.pflags.subOnce = TRUE; | |
2889 | else if (**pp == 'W') | 2889 | else if (**pp == 'W') | |
2890 | oneBigWord = TRUE; | 2890 | oneBigWord = TRUE; | |
2891 | else | 2891 | else | |
2892 | break; | 2892 | break; | |
2893 | } | 2893 | } | |
2894 | 2894 | |||
2895 | if (!(st->expr->eflags & VARE_WANTRES)) { | |||
2896 | free(args.replace); | |||
2897 | free(re); | |||
2898 | return AMR_OK; | |||
2899 | } | |||
2900 | ||||
2895 | error = regcomp(&args.re, re, REG_EXTENDED); | 2901 | error = regcomp(&args.re, re, REG_EXTENDED); | |
2896 | free(re); | 2902 | free(re); | |
2897 | if (error != 0) { | 2903 | if (error != 0) { | |
2898 | VarREError(error, &args.re, "Regex compilation error"); | 2904 | VarREError(error, &args.re, "Regex compilation error"); | |
2899 | free(args.replace); | 2905 | free(args.replace); | |
2900 | return AMR_CLEANUP; | 2906 | return AMR_CLEANUP; | |
2901 | } | 2907 | } | |
2902 | 2908 | |||
2903 | args.nsub = args.re.re_nsub + 1; | 2909 | args.nsub = args.re.re_nsub + 1; | |
2904 | if (args.nsub > 10) | 2910 | if (args.nsub > 10) | |
2905 | args.nsub = 10; | 2911 | args.nsub = 10; | |
2906 | 2912 | |||
2907 | ModifyWords(st, ModifyWord_SubstRegex, &args, oneBigWord); | 2913 | ModifyWords(st, ModifyWord_SubstRegex, &args, oneBigWord); |
--- src/usr.bin/make/unit-tests/opt-debug-lint.exp 2021/03/14 10:45:51 1.15
+++ src/usr.bin/make/unit-tests/opt-debug-lint.exp 2021/03/14 10:57:12 1.16
@@ -1,9 +1,8 @@ | @@ -1,9 +1,8 @@ | |||
1 | make: "opt-debug-lint.mk" line 19: Variable "X" is undefined | 1 | make: "opt-debug-lint.mk" line 19: Variable "X" is undefined | |
2 | make: "opt-debug-lint.mk" line 41: Variable "UNDEF" is undefined | 2 | make: "opt-debug-lint.mk" line 41: Variable "UNDEF" is undefined | |
3 | make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "L" | 3 | make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "L" | |
4 | make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "P" | 4 | make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "P" | |
5 | make: "opt-debug-lint.mk" line 69: Unknown modifier "${" | 5 | make: "opt-debug-lint.mk" line 69: Unknown modifier "${" | |
6 | make: Regex compilation error: (details omitted) | |||
7 | make: Fatal errors encountered -- cannot continue | 6 | make: Fatal errors encountered -- cannot continue | |
8 | make: stopped in unit-tests | 7 | make: stopped in unit-tests | |
9 | exit status 1 | 8 | exit status 1 |
--- src/usr.bin/make/unit-tests/opt-debug-lint.mk 2021/03/14 10:45:51 1.13
+++ src/usr.bin/make/unit-tests/opt-debug-lint.mk 2021/03/14 10:57:12 1.14
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: opt-debug-lint.mk,v 1.13 2021/03/14 10:45:51 rillig Exp $ | 1 | # $NetBSD: opt-debug-lint.mk,v 1.14 2021/03/14 10:57:12 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for the -dL command line option, which runs additional checks | 3 | # Tests for the -dL command line option, which runs additional checks | |
4 | # to catch common mistakes, such as unclosed variable expressions. | 4 | # to catch common mistakes, such as unclosed variable expressions. | |
5 | 5 | |||
6 | .MAKEFLAGS: -dL | 6 | .MAKEFLAGS: -dL | |
7 | 7 | |||
8 | # Since 2020-09-13, undefined variables that are used on the left-hand side | 8 | # Since 2020-09-13, undefined variables that are used on the left-hand side | |
9 | # of a condition at parse time get a proper error message. Before, the | 9 | # of a condition at parse time get a proper error message. Before, the | |
10 | # error message was "Malformed conditional" only, which was wrong and | 10 | # error message was "Malformed conditional" only, which was wrong and | |
11 | # misleading. The form of the condition is totally fine, it's the evaluation | 11 | # misleading. The form of the condition is totally fine, it's the evaluation | |
12 | # that fails. | 12 | # that fails. | |
13 | # | 13 | # | |
14 | # Since 2020-09-13, the "Malformed conditional" error message is not printed | 14 | # Since 2020-09-13, the "Malformed conditional" error message is not printed | |
@@ -67,26 +67,29 @@ ${UNDEF}: ${UNDEF} | @@ -67,26 +67,29 @@ ${UNDEF}: ${UNDEF} | |||
67 | # since make always fell back trying to parse the indirect modifier as a | 67 | # since make always fell back trying to parse the indirect modifier as a | |
68 | # SysV modifier. | 68 | # SysV modifier. | |
69 | .if ${value:${:UL}PL} != "LPL}" # FIXME: "LPL}" is unexpected here. | 69 | .if ${value:${:UL}PL} != "LPL}" # FIXME: "LPL}" is unexpected here. | |
70 | . error ${value:${:UL}PL} | 70 | . error ${value:${:UL}PL} | |
71 | .endif | 71 | .endif | |
72 | 72 | |||
73 | # Typically, an indirect modifier is followed by a colon or the closing | 73 | # Typically, an indirect modifier is followed by a colon or the closing | |
74 | # brace. This one isn't, therefore make falls back to parsing it as the SysV | 74 | # brace. This one isn't, therefore make falls back to parsing it as the SysV | |
75 | # modifier ":lue=lid". | 75 | # modifier ":lue=lid". | |
76 | .if ${value:L:${:Ulue}=${:Ulid}} != "valid" | 76 | .if ${value:L:${:Ulue}=${:Ulid}} != "valid" | |
77 | . error | 77 | . error | |
78 | .endif | 78 | .endif | |
79 | 79 | |||
80 | # Before var.c 1.XXX from 2021-03-14, the whole variable text was evaluated | 80 | # In lint mode, the whole variable text is evaluated to check for unclosed | |
81 | # to check for unclosed expressions and unknown operators. During this check, | 81 | # expressions and unknown operators. During this check, the subexpression | |
82 | # the subexpression '${:U2}' was not expanded, instead it was copied verbatim | 82 | # '${:U2}' is not expanded, instead it is copied verbatim into the regular | |
83 | # into the regular expression, which was '.*=.{1,${:U2}}$'. This regular | 83 | # expression, leading to '.*=.{1,${:U2}}$'. | |
84 | # expression was then compiled (despite VARE_WANTRES being unset), which | 84 | # | |
85 | # resulted in a wrong error message. | 85 | # Before var.c 1.856 from 2021-03-14, this regular expression was then | |
86 | # compiled even though that was not necessary for checking the syntax at the | |||
87 | # level of variable expressions. The unexpanded '$' then resulted in a wrong | |||
88 | # error message. | |||
86 | # | 89 | # | |
87 | # This only happened in lint mode since in default mode the early check for | 90 | # This only happened in lint mode since in default mode the early check for | |
88 | # unclosed expressions and unknown modifiers is skipped. | 91 | # unclosed expressions and unknown modifiers is skipped. | |
89 | # | 92 | # | |
90 | # See VarCheckSyntax, ApplyModifier_Regex. | 93 | # See VarCheckSyntax, ApplyModifier_Regex. | |
91 | # | 94 | # | |
92 | VARMOD_REGEX= ${:UA=111 B=222 C=33:C/.*=.{1,${:U2}}$//g} | 95 | VARMOD_REGEX= ${:UA=111 B=222 C=33:C/.*=.{1,${:U2}}$//g} |