Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make(1): fix evaluation of unreachable conditions



details:   https://anonhg.NetBSD.org/src/rev/9aaf4dd14a15
branches:  trunk
changeset: 935268:9aaf4dd14a15
user:      rillig <rillig%NetBSD.org@localhost>
date:      Sun Jun 28 11:06:26 2020 +0000

description:
make(1): fix evaluation of unreachable conditions

Since 2015-10-11, make had evaluated unreachable conditions even though
the manual page said it didn't.

diffstat:

 usr.bin/make/cond.c                    |  28 +++++++++-----------
 usr.bin/make/unit-tests/cond-short.exp |   6 +++-
 usr.bin/make/unit-tests/cond-short.mk  |  45 ++++++++++++++++++++++++---------
 3 files changed, 50 insertions(+), 29 deletions(-)

diffs (200 lines):

diff -r ef267a9fbb7b -r 9aaf4dd14a15 usr.bin/make/cond.c
--- a/usr.bin/make/cond.c       Sun Jun 28 09:42:40 2020 +0000
+++ b/usr.bin/make/cond.c       Sun Jun 28 11:06:26 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $      */
+/*     $NetBSD: cond.c,v 1.76 2020/06/28 11:06:26 rillig Exp $ */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $";
+static char rcsid[] = "$NetBSD: cond.c,v 1.76 2020/06/28 11:06:26 rillig Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)cond.c     8.2 (Berkeley) 1/2/94";
 #else
-__RCSID("$NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $");
+__RCSID("$NetBSD: cond.c,v 1.76 2020/06/28 11:06:26 rillig Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -146,7 +146,7 @@
  * last two fields are stored in condInvert and condDefProc, respectively.
  */
 static void CondPushBack(Token);
-static int CondGetArg(char **, char **, const char *);
+static int CondGetArg(Boolean, char **, char **, const char *);
 static Boolean CondDoDefined(int, const char *);
 static int CondStrMatch(const void *, const void *);
 static Boolean CondDoMake(int, const char *);
@@ -225,9 +225,6 @@
  * CondGetArg --
  *     Find the argument of a built-in function.
  *
- * Input:
- *     parens          TRUE if arg should be bounded by parens
- *
  * Results:
  *     The length of the argument and the address of the argument.
  *
@@ -238,7 +235,7 @@
  *-----------------------------------------------------------------------
  */
 static int
-CondGetArg(char **linePtr, char **argPtr, const char *func)
+CondGetArg(Boolean doEval, char **linePtr, char **argPtr, const char *func)
 {
     char         *cp;
     int                  argLen;
@@ -290,7 +287,8 @@
            int         len;
            void        *freeIt;
 
-           cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES,
+           cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|
+                           (doEval ? VARF_WANTRES : 0),
                            &len, &freeIt);
            Buf_AddBytes(&buf, strlen(cp2), cp2);
            free(freeIt);
@@ -577,7 +575,7 @@
            /* if we are in quotes, then an undefined variable is ok */
            str = Var_Parse(condExpr, VAR_CMD,
                            ((!qt && doEval) ? VARF_UNDEFERR : 0) |
-                           VARF_WANTRES, &len, freeIt);
+                           (doEval ? VARF_WANTRES : 0), &len, freeIt);
            if (str == var_Error) {
                if (*freeIt) {
                    free(*freeIt);
@@ -813,7 +811,7 @@
 }
 
 static int
-get_mpt_arg(char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED)
+get_mpt_arg(Boolean doEval, char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED)
 {
     /*
      * Use Var_Parse to parse the spec in parens and return
@@ -827,7 +825,7 @@
     /* We do all the work here and return the result as the length */
     *argPtr = NULL;
 
-    val = Var_Parse(cp - 1, VAR_CMD, VARF_WANTRES, &length, &freeIt);
+    val = Var_Parse(cp - 1, VAR_CMD, doEval ? VARF_WANTRES : 0, &length, &freeIt);
     /*
      * Advance *linePtr to beyond the closing ). Note that
      * we subtract one because 'length' is calculated from 'cp - 1'.
@@ -864,7 +862,7 @@
     static const struct fn_def {
        const char  *fn_name;
        int         fn_name_len;
-        int         (*fn_getarg)(char **, char **, const char *);
+        int         (*fn_getarg)(Boolean, char **, char **, const char *);
        Boolean     (*fn_proc)(int, const char *);
     } fn_defs[] = {
        { "defined",   7, CondGetArg, CondDoDefined },
@@ -892,7 +890,7 @@
        if (*cp != '(')
            break;
 
-       arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name);
+       arglen = fn_def->fn_getarg(doEval, &cp, &arg, fn_def->fn_name);
        if (arglen <= 0) {
            condExpr = cp;
            return arglen < 0 ? TOK_ERROR : TOK_FALSE;
@@ -917,7 +915,7 @@
      * would be invalid if we did "defined(a)" - so instead treat as an
      * expression.
      */
-    arglen = CondGetArg(&cp, &arg, NULL);
+    arglen = CondGetArg(doEval, &cp, &arg, NULL);
     for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++)
        continue;
     if (*cp1 == '=' || *cp1 == '!')
diff -r ef267a9fbb7b -r 9aaf4dd14a15 usr.bin/make/unit-tests/cond-short.exp
--- a/usr.bin/make/unit-tests/cond-short.exp    Sun Jun 28 09:42:40 2020 +0000
+++ b/usr.bin/make/unit-tests/cond-short.exp    Sun Jun 28 11:06:26 2020 +0000
@@ -1,5 +1,7 @@
-unexpected and
 expected and
-unexpected or
+expected and exists
+expected and empty
 expected or
+expected or exists
+expected or empty
 exit status 0
diff -r ef267a9fbb7b -r 9aaf4dd14a15 usr.bin/make/unit-tests/cond-short.mk
--- a/usr.bin/make/unit-tests/cond-short.mk     Sun Jun 28 09:42:40 2020 +0000
+++ b/usr.bin/make/unit-tests/cond-short.mk     Sun Jun 28 11:06:26 2020 +0000
@@ -1,18 +1,13 @@
-# $NetBSD: cond-short.mk,v 1.1 2020/06/28 09:42:40 rillig Exp $
+# $NetBSD: cond-short.mk,v 1.2 2020/06/28 11:06:26 rillig Exp $
 #
 # Demonstrates that in conditions, the right-hand side of an && or ||
-# is evaluated even though it cannot influence the result.
-#
-# This is unexpected for several reasons:
+# is only evaluated if it can actually influence the result.
 #
-# 1.  The manual page says: "bmake will only evaluate a conditional as
-#     far as is necessary to determine its value."
+# Between 2015-10-11 and 2020-06-28, the right-hand side of an && or ||
+# operator was always evaluated, which was wrong.
 #
-# 2.  It differs from the way that these operators are evaluated in
-#     almost all other programming languages.
-#
-# 3.  In cond.c there are lots of doEval variables.
-#
+
+# The && operator.
 
 .if 0 && ${echo "unexpected and" 1>&2 :L:sh}
 .endif
@@ -20,13 +15,39 @@
 .if 1 && ${echo "expected and" 1>&2 :L:sh}
 .endif
 
+.if 0 && exists(nonexistent${echo "unexpected and exists" 1>&2 :L:sh})
+.endif
+
+.if 1 && exists(nonexistent${echo "expected and exists" 1>&2 :L:sh})
+.endif
+
+.if 0 && empty(${echo "unexpected and empty" 1>&2 :L:sh})
+.endif
+
+.if 1 && empty(${echo "expected and empty" 1>&2 :L:sh})
+.endif
+
+# The || operator.
+
 .if 1 || ${echo "unexpected or" 1>&2 :L:sh}
 .endif
 
 .if 0 || ${echo "expected or" 1>&2 :L:sh}
 .endif
 
-# The following paragraphs demonstrate the workaround.
+.if 1 || exists(nonexistent${echo "unexpected or exists" 1>&2 :L:sh})
+.endif
+
+.if 0 || exists(nonexistent${echo "expected or exists" 1>&2 :L:sh})
+.endif
+
+.if 1 || empty(${echo "unexpected or empty" 1>&2 :L:sh})
+.endif
+
+.if 0 || empty(${echo "expected or empty" 1>&2 :L:sh})
+.endif
+
+# Unreachable nested conditions are skipped completely as well.
 
 .if 0
 .  if ${echo "unexpected nested and" 1>&2 :L:sh}



Home | Main Index | Thread Index | Old Index