Module Name: src Committed By: sjg Date: Tue May 5 21:51:09 UTC 2015
Modified Files: src/usr.bin/make: cond.c nonints.h var.c src/usr.bin/make/unit-tests: Makefile Added Files: src/usr.bin/make/unit-tests: cond2.exp cond2.mk Log Message: When evaluating condtionals from .if we want to require that the lhs is a variable reference, a number or a quoted string. This helps avoid subtle bugs caused by typos. When conditionals are being evaluated during variable expansion we cannot be as strict becuase lhs will already have been expanded. We therefor pass a boolean to Cond_EvalExpression to tell it how lhs should be treated. Add unit-tests/cond2.mk to test the above Reviewed by: christos, joerg To generate a diff of this commit: cvs rdiff -u -r1.67 -r1.68 src/usr.bin/make/cond.c src/usr.bin/make/nonints.h cvs rdiff -u -r1.191 -r1.192 src/usr.bin/make/var.c cvs rdiff -u -r1.51 -r1.52 src/usr.bin/make/unit-tests/Makefile cvs rdiff -u -r0 -r1.1 src/usr.bin/make/unit-tests/cond2.exp \ src/usr.bin/make/unit-tests/cond2.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/cond.c diff -u src/usr.bin/make/cond.c:1.67 src/usr.bin/make/cond.c:1.68 --- src/usr.bin/make/cond.c:1.67 Sat Nov 3 13:59:27 2012 +++ src/usr.bin/make/cond.c Tue May 5 21:51:09 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: cond.c,v 1.67 2012/11/03 13:59:27 christos Exp $ */ +/* $NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg 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.67 2012/11/03 13:59:27 christos Exp $"; +static char rcsid[] = "$NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg 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.67 2012/11/03 13:59:27 christos Exp $"); +__RCSID("$NetBSD: cond.c,v 1.68 2015/05/05 21:51:09 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -181,6 +181,15 @@ static Token condPushBack=TOK_NONE; /* static unsigned int cond_depth = 0; /* current .if nesting level */ static unsigned int cond_min_depth = 0; /* depth at makefile open */ +/* + * Indicate when we should be strict about lhs of comparisons. + * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc) + * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers + * since lhs is already expanded and we cannot tell if + * it was a variable reference or not. + */ +static Boolean lhsStrict; + static int istoken(const char *str, const char *tok, size_t len) { @@ -517,7 +526,7 @@ CondCvtArg(char *str, double *value) */ /* coverity:[+alloc : arg-*2] */ static char * -CondGetString(Boolean doEval, Boolean *quoted, void **freeIt) +CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) { Buffer buf; char *cp; @@ -601,6 +610,16 @@ CondGetString(Boolean doEval, Boolean *q condExpr--; /* don't skip over next char */ break; default: + if (strictLHS && !qt && *start != '$' && + !isdigit((unsigned char) *start)) { + /* lhs must be quoted, a variable reference or number */ + if (*freeIt) { + free(*freeIt); + *freeIt = NULL; + } + str = NULL; + goto cleanup; + } Buf_AddByte(&buf, *condExpr); break; } @@ -648,7 +667,7 @@ compare_expression(Boolean doEval) * Parse the variable spec and skip over it, saving its * value in lhs. */ - lhs = CondGetString(doEval, &lhsQuoted, &lhsFree); + lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict); if (!lhs) goto done; @@ -709,7 +728,7 @@ compare_expression(Boolean doEval) goto done; } - rhs = CondGetString(doEval, &rhsQuoted, &rhsFree); + rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE); if (!rhs) goto done; @@ -1135,7 +1154,7 @@ CondE(Boolean doEval) *----------------------------------------------------------------------- */ int -Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint) +Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint, Boolean strictLHS) { static const struct If *dflt_info; const struct If *sv_if_info = if_info; @@ -1143,6 +1162,8 @@ Cond_EvalExpression(const struct If *inf Token sv_condPushBack = condPushBack; int rval; + lhsStrict = strictLHS; + while (*line == ' ' || *line == '\t') line++; @@ -1359,7 +1380,7 @@ Cond_Eval(char *line) } /* And evaluate the conditional expresssion */ - if (Cond_EvalExpression(ifp, line, &value, 1) == COND_INVALID) { + if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) { /* Syntax error in conditional, error message already output. */ /* Skip everything to matching .endif */ cond_state[cond_depth] = SKIP_TO_ELSE; Index: src/usr.bin/make/nonints.h diff -u src/usr.bin/make/nonints.h:1.67 src/usr.bin/make/nonints.h:1.68 --- src/usr.bin/make/nonints.h:1.67 Sun Sep 7 20:55:34 2014 +++ src/usr.bin/make/nonints.h Tue May 5 21:51:09 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: nonints.h,v 1.67 2014/09/07 20:55:34 joerg Exp $ */ +/* $NetBSD: nonints.h,v 1.68 2015/05/05 21:51:09 sjg Exp $ */ /*- * Copyright (c) 1988, 1989, 1990, 1993 @@ -91,7 +91,7 @@ int Compat_Make(void *, void *); /* cond.c */ struct If; -int Cond_EvalExpression(const struct If *, char *, Boolean *, int); +int Cond_EvalExpression(const struct If *, char *, Boolean *, int, Boolean); int Cond_Eval(char *); void Cond_restore_depth(unsigned int); unsigned int Cond_save_depth(void); Index: src/usr.bin/make/var.c diff -u src/usr.bin/make/var.c:1.191 src/usr.bin/make/var.c:1.192 --- src/usr.bin/make/var.c:1.191 Sun Sep 14 02:32:51 2014 +++ src/usr.bin/make/var.c Tue May 5 21:51:09 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $ */ +/* $NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $"; +static char rcsid[] = "$NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $"); +__RCSID("$NetBSD: var.c,v 1.192 2015/05/05 21:51:09 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -3260,7 +3260,7 @@ ApplyModifiers(char *nstr, const char *t termc = *--cp; delim = '\0'; - if (Cond_EvalExpression(NULL, v->name, &value, 0) + if (Cond_EvalExpression(NULL, v->name, &value, 0, FALSE) == COND_INVALID) { Error("Bad conditional expression `%s' in %s?%s:%s", v->name, v->name, pattern.lhs, pattern.rhs); Index: src/usr.bin/make/unit-tests/Makefile diff -u src/usr.bin/make/unit-tests/Makefile:1.51 src/usr.bin/make/unit-tests/Makefile:1.52 --- src/usr.bin/make/unit-tests/Makefile:1.51 Mon Oct 20 23:21:11 2014 +++ src/usr.bin/make/unit-tests/Makefile Tue May 5 21:51:09 2015 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.51 2014/10/20 23:21:11 sjg Exp $ +# $NetBSD: Makefile,v 1.52 2015/05/05 21:51:09 sjg Exp $ # # Unit tests for make(1) # The main targets are: @@ -23,6 +23,7 @@ UNIT_TESTS:= ${.PARSEDIR} TESTNAMES= \ comment \ cond1 \ + cond2 \ error \ export \ export-all \ Added files: Index: src/usr.bin/make/unit-tests/cond2.exp diff -u /dev/null src/usr.bin/make/unit-tests/cond2.exp:1.1 --- /dev/null Tue May 5 21:51:09 2015 +++ src/usr.bin/make/unit-tests/cond2.exp Tue May 5 21:51:09 2015 @@ -0,0 +1,7 @@ +make: Bad conditional expression ` == "empty"' in == "empty"?oops:ok +make: "cond2.mk" line 13: Malformed conditional ({TEST_TYPO} == "Ok") +TEST_NOT_SET is empty or not defined +make: "cond2.mk" line 20: Malformed conditional (${TEST_NOT_SET} == "empty") +make: Fatal errors encountered -- cannot continue +make: stopped in unit-tests +exit status 1 Index: src/usr.bin/make/unit-tests/cond2.mk diff -u /dev/null src/usr.bin/make/unit-tests/cond2.mk:1.1 --- /dev/null Tue May 5 21:51:09 2015 +++ src/usr.bin/make/unit-tests/cond2.mk Tue May 5 21:51:09 2015 @@ -0,0 +1,25 @@ +# $Id: cond2.mk,v 1.1 2015/05/05 21:51:09 sjg Exp $ + +TEST_UNAME_S= NetBSD + +# this should be ok +X:= ${${TEST_UNAME_S} == "NetBSD":?Ok:fail} +.if $X == "Ok" +Y= good +.endif +# expect: Bad conditional expression ` == "empty"' in == "empty"?oops:ok +X:= ${${TEST_NOT_SET} == "empty":?oops:ok} +# expect: Malformed conditional ({TEST_TYPO} == "Ok") +.if {TEST_TYPO} == "Ok" +Y= oops +.endif +.if empty(TEST_NOT_SET) +Y!= echo TEST_NOT_SET is empty or not defined >&2; echo +.endif +# expect: Malformed conditional (${TEST_NOT_SET} == "empty") +.if ${TEST_NOT_SET} == "empty" +Y= oops +.endif + +all: + @echo $@