Mon Nov 2 21:34:40 2020 UTC ()
make(1): fix error handling on parse errors in variable expressions

This change doesn't change any of the unit tests since the error
handling code is not yet complete, see the many "handle errors" in the
code.  Nevertheless, the "out_FALSE_res = VPR_PARSE_MSG" was wrong since
the error message was only printed in lint mode, not in default mode.


(rillig)
diff -r1.651 -r1.652 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/11/02 21:24:23 1.651
+++ src/usr.bin/make/var.c 2020/11/02 21:34:40 1.652
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: var.c,v 1.651 2020/11/02 21:24:23 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.652 2020/11/02 21:34:40 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.
@@ -120,27 +120,27 @@ @@ -120,27 +120,27 @@
120#include <regex.h> 120#include <regex.h>
121#endif 121#endif
122#include <errno.h> 122#include <errno.h>
123#include <inttypes.h> 123#include <inttypes.h>
124#include <limits.h> 124#include <limits.h>
125#include <time.h> 125#include <time.h>
126 126
127#include "make.h" 127#include "make.h"
128#include "dir.h" 128#include "dir.h"
129#include "job.h" 129#include "job.h"
130#include "metachar.h" 130#include "metachar.h"
131 131
132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
133MAKE_RCSID("$NetBSD: var.c,v 1.651 2020/11/02 21:24:23 rillig Exp $"); 133MAKE_RCSID("$NetBSD: var.c,v 1.652 2020/11/02 21:34:40 rillig Exp $");
134 134
135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
139 139
140ENUM_FLAGS_RTTI_3(VarEvalFlags, 140ENUM_FLAGS_RTTI_3(VarEvalFlags,
141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
142 142
143/* 143/*
144 * This lets us tell if we have replaced the original environ 144 * This lets us tell if we have replaced the original environ
145 * (which we cannot free). 145 * (which we cannot free).
146 */ 146 */
@@ -3534,80 +3534,82 @@ ParseVarname(const char **pp, char start @@ -3534,80 +3534,82 @@ ParseVarname(const char **pp, char start
3534 /* TODO: handle errors */ 3534 /* TODO: handle errors */
3535 Buf_AddStr(&buf, nested_val); 3535 Buf_AddStr(&buf, nested_val);
3536 free(nested_val_freeIt); 3536 free(nested_val_freeIt);
3537 } else { 3537 } else {
3538 Buf_AddByte(&buf, *p); 3538 Buf_AddByte(&buf, *p);
3539 p++; 3539 p++;
3540 } 3540 }
3541 } 3541 }
3542 *pp = p; 3542 *pp = p;
3543 *out_varname_len = Buf_Len(&buf); 3543 *out_varname_len = Buf_Len(&buf);
3544 return Buf_Destroy(&buf, FALSE); 3544 return Buf_Destroy(&buf, FALSE);
3545} 3545}
3546 3546
3547static Boolean 3547static VarParseResult
3548ValidShortVarname(char varname, const char *start) 3548ValidShortVarname(char varname, const char *start)
3549{ 3549{
3550 switch (varname) { 3550 switch (varname) {
3551 case '\0': 3551 case '\0':
3552 case ')': 3552 case ')':
3553 case '}': 3553 case '}':
3554 case ':': 3554 case ':':
3555 case '$': 3555 case '$':
3556 break; /* and continue below */ 3556 break; /* and continue below */
3557 default: 3557 default:
3558 return TRUE; 3558 return VPR_OK;
3559 } 3559 }
3560 3560
3561 if (!DEBUG(LINT)) 3561 if (!DEBUG(LINT))
3562 return FALSE; 3562 return VPR_PARSE_SILENT;
3563 3563
3564 if (varname == '$') 3564 if (varname == '$')
3565 Parse_Error(PARSE_FATAL, 3565 Parse_Error(PARSE_FATAL,
3566 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3566 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3567 else if (varname == '\0') 3567 else if (varname == '\0')
3568 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3568 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3569 else 3569 else
3570 Parse_Error(PARSE_FATAL, 3570 Parse_Error(PARSE_FATAL,
3571 "Invalid variable name '%c', at \"%s\"", varname, start); 3571 "Invalid variable name '%c', at \"%s\"", varname, start);
3572 3572
3573 return FALSE; 3573 return VPR_PARSE_MSG;
3574} 3574}
3575 3575
3576/* Parse a single-character variable name such as $V or $@. 3576/* Parse a single-character variable name such as $V or $@.
3577 * Return whether to continue parsing. */ 3577 * Return whether to continue parsing. */
3578static Boolean 3578static Boolean
3579ParseVarnameShort( 3579ParseVarnameShort(
3580 char startc, 3580 char startc,
3581 const char **pp, 3581 const char **pp,
3582 GNode *ctxt, 3582 GNode *ctxt,
3583 VarEvalFlags eflags, 3583 VarEvalFlags eflags,
3584 VarParseResult *out_FALSE_res, 3584 VarParseResult *out_FALSE_res,
3585 const char **out_FALSE_val, 3585 const char **out_FALSE_val,
3586 Var **out_TRUE_var 3586 Var **out_TRUE_var
3587) { 3587) {
3588 char name[2]; 3588 char name[2];
3589 Var *v; 3589 Var *v;
 3590 VarParseResult vpr;
3590 3591
3591 /* 3592 /*
3592 * If it's not bounded by braces of some sort, life is much simpler. 3593 * If it's not bounded by braces of some sort, life is much simpler.
3593 * We just need to check for the first character and return the 3594 * We just need to check for the first character and return the
3594 * value if it exists. 3595 * value if it exists.
3595 */ 3596 */
3596 3597
3597 if (!ValidShortVarname(startc, *pp)) { 3598 vpr = ValidShortVarname(startc, *pp);
 3599 if (vpr != VPR_OK) {
3598 (*pp)++; 3600 (*pp)++;
3599 *out_FALSE_val = var_Error; 3601 *out_FALSE_val = var_Error;
3600 *out_FALSE_res = VPR_PARSE_MSG; 3602 *out_FALSE_res = vpr;
3601 return FALSE; 3603 return FALSE;
3602 } 3604 }
3603 3605
3604 name[0] = startc; 3606 name[0] = startc;
3605 name[1] = '\0'; 3607 name[1] = '\0';
3606 v = VarFind(name, ctxt, TRUE); 3608 v = VarFind(name, ctxt, TRUE);
3607 if (v == NULL) { 3609 if (v == NULL) {
3608 *pp += 2; 3610 *pp += 2;
3609 3611
3610 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3612 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3611 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3613 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3612 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3614 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3613 *out_FALSE_res = VPR_UNDEF_MSG; 3615 *out_FALSE_res = VPR_UNDEF_MSG;