diff options
author | Eric Blake <ebb9@byu.net> | 2008-02-05 11:41:05 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-02-10 14:43:13 -0700 |
commit | fd9f6463352aee342c4061b5df9d0f4bf56742c7 (patch) | |
tree | 647390c9599b49def1a904c538595bff4d29cb26 | |
parent | 948d1ed0ca4089c2db579fe3d8b3ce172b3e616f (diff) | |
download | m4-fd9f6463352aee342c4061b5df9d0f4bf56742c7.tar.gz |
Stage28: allow NUL in warning messages
-rw-r--r-- | doc/m4.texinfo | 38 | ||||
-rw-r--r-- | examples/null.err | bin | 1078 -> 3084 bytes | |||
-rw-r--r-- | examples/null.m4 | bin | 6667 -> 6620 bytes | |||
-rw-r--r-- | examples/null.out | bin | 553 -> 572 bytes | |||
-rw-r--r-- | m4/gnulib-cache.m4 | 2 | ||||
-rw-r--r-- | src/builtin.c | 130 | ||||
-rw-r--r-- | src/debug.c | 19 | ||||
-rw-r--r-- | src/eval.c | 9 | ||||
-rw-r--r-- | src/format.c | 55 | ||||
-rw-r--r-- | src/freeze.c | 13 | ||||
-rw-r--r-- | src/m4.c | 13 | ||||
-rw-r--r-- | src/m4.h | 2 | ||||
-rw-r--r-- | src/path.c | 4 |
13 files changed, 192 insertions, 93 deletions
diff --git a/doc/m4.texinfo b/doc/m4.texinfo index eb2a6673..0f5c53ef 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -43,7 +43,7 @@ This manual is for @acronym{GNU} M4 (version @value{VERSION}, @value{UPDATED}), a package containing an implementation of the m4 macro language. Copyright @copyright{} 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, -2006, 2007, 2008 Free Software Foundation, Inc. +2006, 2007, 2008, 2009 Free Software Foundation, Inc. @quotation Permission is granted to copy, distribute and/or modify this document @@ -935,14 +935,16 @@ exception of the @sc{nul} character (the zero byte @samp{'\0'}). @comment xout: null.out @comment xerr: null.err +@comment status: 1 @example define(`m4exit')include(`null.m4')dnl @end example -@comment status: 2 +@comment status: 1 @example include(`null.m4') @result{}# This file tests m4 behavior on NUL bytes. +@error{}m4:examples/null.m4:5: Warning: m4exit: non-numeric argument `2\0002' @end example @end ignore @@ -6087,10 +6089,10 @@ eval(`2 = 2') @error{}m4:stdin:1: Warning: eval: recommend ==, not =, for equality @result{}1 eval(`++0') -@error{}m4:stdin:2: eval: invalid operator: ++0 +@error{}m4:stdin:2: eval: invalid operator: `++0' @result{} eval(`0 |= 1') -@error{}m4:stdin:3: eval: invalid operator: 0 |= 1 +@error{}m4:stdin:3: eval: invalid operator: `0 |= 1' @result{} @end example @@ -6133,12 +6135,12 @@ eval(`+ + - ~ ! ~ 0') eval(`2 || 1 / 0') @result{}1 eval(`0 || 1 / 0') -@error{}m4:stdin:9: Warning: eval: divide by zero: 0 || 1 / 0 +@error{}m4:stdin:9: Warning: eval: divide by zero: `0 || 1 / 0' @result{} eval(`0 && 1 % 0') @result{}0 eval(`2 && 1 % 0') -@error{}m4:stdin:11: Warning: eval: modulo by zero: 2 && 1 % 0 +@error{}m4:stdin:11: Warning: eval: modulo by zero: `2 && 1 % 0' @result{} @end example @@ -6159,9 +6161,9 @@ eval(`2 ** 0') @result{}1 eval(`0 ** 0') @result{} -@error{}m4:stdin:5: Warning: eval: divide by zero: 0 ** 0 +@error{}m4:stdin:5: Warning: eval: divide by zero: `0 ** 0' eval(`4 ** -2') -@error{}m4:stdin:6: Warning: eval: negative exponent: 4 ** -2 +@error{}m4:stdin:6: Warning: eval: negative exponent: `4 ** -2' @result{} @end example @@ -6206,7 +6208,7 @@ square(square(`5')` + 1') define(`foo', `666') @result{} eval(`foo / 6') -@error{}m4:stdin:11: Warning: eval: bad expression: foo / 6 +@error{}m4:stdin:11: Warning: eval: bad expression: `foo / 6' @result{} eval(foo / 6) @result{}111 @@ -6659,10 +6661,12 @@ define(`foo', `errprint(`oops')') syscmd(`rm -f foo-??????')sysval @result{}0 define(`file1', maketemp(`foo-XXXXXX'))dnl +@error{}m4:stdin:3: Warning: maketemp: recommend using mkstemp instead ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ', `no file', `created') @result{}created define(`file2', maketemp(`foo-XX'))dnl +@error{}m4:stdin:6: Warning: maketemp: recommend using mkstemp instead define(`file3', mkstemp(`foo-XXXXXX'))dnl ifelse(len(defn(`file1')), len(defn(`file2')), `same length', `different') @@ -7082,6 +7086,20 @@ divert(1)undivert(null.out)' | ]__program__[ -F in.m4f \ ])dnl @error{}divnum #-- 3 0 @end example + +@c Do we reject unexpected NUL bytes? + +@example +ifdef(`__unix__', , + `errprint(` skipping: syscmd does not have unix semantics +')m4exit(`77')')dnl +changequote(`[', `]')dnl +syscmd([printf '#bogus\nV1\nF3,4\nlenlen\0\n' > in.m4f \ + && ]__program__[ -R in.m4f \ + && rm in.m4f])sysval +@error{}m4: ill-formed frozen file, invalid builtin `len\0' encountered +@result{}1 +@end example @end ignore When an @code{m4} run is to be frozen, the automatic undiversion @@ -7615,7 +7633,7 @@ forloop(`', `1', `2', ` odd iterator name') forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')') @result{} 0xa 0xb 0xc forloop(`i', `a', `b', `non-numeric bounds') -@error{}m4:stdin:6: Warning: eval: bad expression (bad input): (b) >= (a) +@error{}m4:stdin:6: Warning: eval: bad input in expression: `(b) >= (a)' @result{} @end example diff --git a/examples/null.err b/examples/null.err Binary files differindex 977b3b7c..b0858b3e 100644 --- a/examples/null.err +++ b/examples/null.err diff --git a/examples/null.m4 b/examples/null.m4 Binary files differindex e60aec5a..3dc8d16c 100644 --- a/examples/null.m4 +++ b/examples/null.m4 diff --git a/examples/null.out b/examples/null.out Binary files differindex c2c1cb90..0dfbfdb4 100644 --- a/examples/null.out +++ b/examples/null.out diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 5a1cd9b4..eaa67a2f 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2008 Free Software Foundation, Inc. +# Copyright (C) 2002-2009 Free Software Foundation, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General diff --git a/src/builtin.c b/src/builtin.c index beb2a04a..0c9b9056 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1,7 +1,7 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2000, 2004, 2006, 2007, - 2008 Free Software Foundation, Inc. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2000, 2004, 2006, + 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -562,18 +562,18 @@ bad_argc (const call_info *name, int argc, unsigned int min, unsigned int max) return false; } -/*-------------------------------------------------------------------. -| The function numeric_arg () converts ARG to an int pointed to by | -| VALUEP. If the conversion fails, print error message on behalf of | -| NAME. Return true iff conversion succeeds. | -`-------------------------------------------------------------------*/ +/*------------------------------------------------------------------. +| The function numeric_arg () converts ARG of length LEN to an int | +| pointed to by VALUEP. If the conversion fails, print error | +| message on behalf of NAME. Return true iff conversion succeeds. | +`------------------------------------------------------------------*/ static bool -numeric_arg (const call_info *name, const char *arg, int *valuep) +numeric_arg (const call_info *name, const char *arg, size_t len, int *valuep) { char *endp; - if (*arg == '\0') + if (!len) { *valuep = 0; m4_warn (0, name, _("empty string treated as 0")); @@ -582,9 +582,10 @@ numeric_arg (const call_info *name, const char *arg, int *valuep) { errno = 0; *valuep = strtol (arg, &endp, 10); - if (*endp != '\0') + if (endp - arg != len) { - m4_warn (0, name, _("non-numeric argument `%s'"), arg); + m4_warn (0, name, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, arg, len)); return false; } if (isspace (to_uchar (*arg))) @@ -1070,8 +1071,9 @@ m4_defn (struct obstack *obs, int argc, macro_arguments *argv) b = SYMBOL_FUNC (s); if (b == m4_placeholder) m4_warn (0, me, - _("builtin `%s' requested by frozen file not found"), - ARG (i)); + _("builtin %s requested by frozen file not found"), + quotearg_style_mem (locale_quoting_style, ARG (i), + ARG_LEN (i))); else push_macro (obs, b); break; @@ -1123,7 +1125,14 @@ static int sysval; static void m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv) { - if (bad_argc (arg_info (argv), argc, 1, 1)) + const call_info *me = arg_info (argv); + const char *cmd = ARG (1); + size_t len = ARG_LEN (1); + + if (strlen (cmd) != len) + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, cmd, len)); + if (bad_argc (me, argc, 1, 1) || !*cmd) { /* The empty command is successful. */ sysval = 0; @@ -1131,7 +1140,7 @@ m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv) } debug_flush_files (); - sysval = system (ARG (1)); + sysval = system (cmd); #if FUNC_SYSTEM_BROKEN /* OS/2 has a buggy system() that returns exit status in the lowest eight bits, although pclose() and WEXITSTATUS are defined to return exit @@ -1148,10 +1157,15 @@ static void m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv) { const call_info *me = arg_info (argv); + const char *cmd = ARG (1); + size_t len = ARG_LEN (1); FILE *pin; int ch; - if (bad_argc (me, argc, 1, 1)) + if (strlen (cmd) != len) + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, cmd, len)); + if (bad_argc (me, argc, 1, 1) || !*cmd) { /* The empty command is successful. */ sysval = 0; @@ -1160,10 +1174,11 @@ m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv) debug_flush_files (); errno = 0; - pin = popen (ARG (1), "r"); + pin = popen (cmd, "r"); if (pin == NULL) { - m4_warn (errno, me, _("cannot open pipe to command `%s'"), ARG (1)); + m4_warn (errno, me, _("cannot open pipe to command %s"), + quotearg_style (locale_quoting_style, cmd)); sysval = -1; } else @@ -1200,7 +1215,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv) if (bad_argc (me, argc, 1, 3)) return; - if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), &radix)) + if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), ARG_LEN (2), &radix)) return; if (radix < 1 || radix > 36) @@ -1209,7 +1224,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv) return; } - if (argc >= 4 && !numeric_arg (me, ARG (3), &min)) + if (argc >= 4 && !numeric_arg (me, ARG (3), ARG_LEN (3), &min)) return; if (min < 0) { @@ -1264,7 +1279,7 @@ m4_incr (struct obstack *obs, int argc, macro_arguments *argv) if (bad_argc (me, argc, 1, 1)) return; - if (!numeric_arg (me, ARG (1), &value)) + if (!numeric_arg (me, ARG (1), ARG_LEN (1), &value)) return; shipout_int (obs, value + 1); @@ -1279,7 +1294,7 @@ m4_decr (struct obstack *obs, int argc, macro_arguments *argv) if (bad_argc (me, argc, 1, 1)) return; - if (!numeric_arg (me, ARG (1), &value)) + if (!numeric_arg (me, ARG (1), ARG_LEN (1), &value)) return; shipout_int (obs, value - 1); @@ -1300,7 +1315,7 @@ m4_divert (struct obstack *obs, int argc, macro_arguments *argv) int i = 0; bad_argc (me, argc, 0, 1); - if (argc >= 2 && !numeric_arg (me, ARG (1), &i)) + if (argc >= 2 && !numeric_arg (me, ARG (1), ARG_LEN (1), &i)) return; make_diversion (i); @@ -1339,11 +1354,16 @@ m4_undivert (struct obstack *obs, int argc, macro_arguments *argv) for (i = 1; i < argc; i++) { const char *str = ARG (i); + size_t len = ARG_LEN (i); file = strtol (str, &endp, 10); - if (*endp == '\0' && !isspace (to_uchar (*str))) + if (endp - str == len && !isspace (to_uchar (*str))) insert_diversion (file); else if (no_gnu_extensions) - m4_warn (0, me, _("non-numeric argument `%s'"), str); + m4_warn (0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); + else if (strlen (str) != len) + m4_warn (0, me, _("invalid file name %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else { fp = m4_path_search (str, NULL); @@ -1351,10 +1371,12 @@ m4_undivert (struct obstack *obs, int argc, macro_arguments *argv) { insert_file (fp); if (fclose (fp) == EOF) - m4_warn (errno, me, _("error undiverting `%s'"), str); + m4_warn (errno, me, _("error undiverting %s"), + quotearg_style (locale_quoting_style, str)); } else - m4_warn (errno, me, _("cannot undivert `%s'"), str); + m4_warn (errno, me, _("cannot undivert %s"), + quotearg_style (locale_quoting_style, str)); } } } @@ -1453,15 +1475,23 @@ include (int argc, macro_arguments *argv, bool silent) const call_info *me = arg_info (argv); FILE *fp; char *name; + const char *arg; + size_t len; if (bad_argc (me, argc, 1, 1)) return; - fp = m4_path_search (ARG (1), &name); + arg = ARG (1); + len = ARG_LEN (1); + if (strlen (arg) != len) + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, arg, len)); + fp = m4_path_search (arg, &name); if (fp == NULL) { if (!silent) - m4_error (0, errno, me, _("cannot open `%s'"), ARG (1)); + m4_error (0, errno, me, _("cannot open %s"), + quotearg_style (locale_quoting_style, arg)); return; } @@ -1511,6 +1541,12 @@ mkstemp_helper (struct obstack *obs, const call_info *me, const char *pattern, user forgot to supply them. Output must be quoted if successful. */ obstack_grow (obs, curr_quote.str1, curr_quote.len1); + if (strlen (pattern) < len) + { + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, pattern, len)); + len = strlen (pattern); + } obstack_grow (obs, pattern, len); for (i = 0; len > 0 && i < 6; i++) if (pattern[--len] != 'X') @@ -1522,7 +1558,8 @@ mkstemp_helper (struct obstack *obs, const call_info *me, const char *pattern, fd = mkstemp (name); if (fd < 0) { - m4_warn (errno, me, _("cannot create tempfile `%s'"), pattern); + m4_warn (errno, me, _("cannot create file from template %s"), + quotearg_style (locale_quoting_style, pattern)); obstack_free (obs, obstack_finish (obs)); } else @@ -1541,6 +1578,7 @@ m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv) if (bad_argc (me, argc, 1, 1)) return; + m4_warn (0, me, _("recommend using mkstemp instead")); if (no_gnu_extensions) { /* POSIX states "any trailing 'X' characters [are] replaced with @@ -1562,7 +1600,6 @@ m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv) (unsigned long) getpid ()); char *pid = (char *) obstack_copy0 (scratch, "", 0); - m4_warn (0, me, _("recommend using mkstemp instead")); for (i = len; i > 1; i--) if (str[i - 1] != 'X') break; @@ -1648,7 +1685,7 @@ m4_m4exit (struct obstack *obs, int argc, macro_arguments *argv) /* Warn on bad arguments, but still exit. */ bad_argc (me, argc, 0, 1); - if (argc >= 2 && !numeric_arg (me, ARG (1), &exit_code)) + if (argc >= 2 && !numeric_arg (me, ARG (1), ARG_LEN (1), &exit_code)) exit_code = EXIT_FAILURE; if (exit_code < 0 || exit_code > 255) { @@ -1763,6 +1800,7 @@ m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv) { const call_info *me = arg_info (argv); const char *str = ARG (1); + size_t len = ARG_LEN (1); int new_debug_level; int change_flag; @@ -1775,16 +1813,17 @@ m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv) if (*str == '+' || *str == '-') { change_flag = *str; - new_debug_level = debug_decode (str + 1); + new_debug_level = debug_decode (str + 1, len - 1); } else { change_flag = 0; - new_debug_level = debug_decode (str); + new_debug_level = debug_decode (str, len); } if (new_debug_level < 0) - m4_warn (0, me, _("bad debug flags: `%s'"), str); + m4_warn (0, me, _("bad debug flags: %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else { switch (change_flag) @@ -1819,8 +1858,17 @@ m4_debugfile (struct obstack *obs, int argc, macro_arguments *argv) if (argc == 1) debug_set_output (me, NULL); - else if (!debug_set_output (me, ARG (1))) - m4_warn (errno, me, _("cannot set error file: `%s'"), ARG (1)); + else + { + const char *str = ARG (1); + size_t len = ARG_LEN (1); + if (strlen (str) < len) + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, str, len)); + if (!debug_set_output (me, str)) + m4_warn (errno, me, _("cannot set debug file %s"), + quotearg_style (locale_quoting_style, str)); + } } /* This section contains text processing macros: "len", "index", @@ -1896,10 +1944,10 @@ m4_substr (struct obstack *obs, int argc, macro_arguments *argv) } length = avail = ARG_LEN (1); - if (!numeric_arg (me, ARG (2), &start)) + if (!numeric_arg (me, ARG (2), ARG_LEN (2), &start)) return; - if (argc >= 4 && !numeric_arg (me, ARG (3), &length)) + if (argc >= 4 && !numeric_arg (me, ARG (3), ARG_LEN (3), &length)) return; if (start < 0 || length <= 0 || start >= avail) @@ -2362,8 +2410,8 @@ m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv) void m4_placeholder (struct obstack *obs, int argc, macro_arguments *argv) { - m4_warn (0, NULL, _("builtin `%s' requested by frozen file not found"), - ARG (0)); + m4_warn (0, NULL, _("builtin %s requested by frozen file not found"), + quotearg_style_mem (locale_quoting_style, ARG (0), ARG_LEN (0))); } /*-------------------------------------------------------------------------. diff --git a/src/debug.c b/src/debug.c index c3f85bd6..82f0cbc8 100644 --- a/src/debug.c +++ b/src/debug.c @@ -43,21 +43,26 @@ debug_init (void) obstack_init (&trace); } -/*-----------------------------------------------------------------. -| Function to decode the debugging flags OPTS. Used by main while | -| processing option -d, and by the builtin debugmode (). | -`-----------------------------------------------------------------*/ +/*-------------------------------------------------------------------. +| Function to decode the debugging flags OPTS of length LEN. If LEN | +| is SIZE_MAX, use strlen (OPTS) instead. Used by main while | +| processing option -d, and by the builtin debugmode. | +`-------------------------------------------------------------------*/ int -debug_decode (const char *opts) +debug_decode (const char *opts, size_t len) { int level; - if (opts == NULL || *opts == '\0') + if (!opts) + opts = ""; + if (len == SIZE_MAX) + len = strlen (opts); + if (!len) level = DEBUG_TRACE_DEFAULT; else { - for (level = 0; *opts; opts++) + for (level = 0; len--; opts++) { switch (*opts) { @@ -313,6 +313,8 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) err = EXCESS_INPUT; } + if (err != NO_ERROR) + expr = quotearg_style_mem (locale_quoting_style, expr, len); switch (err) { /* Cases where result is printed. */ @@ -325,8 +327,7 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) /* Cases where error makes result meaningless. */ case MISSING_RIGHT: - m4_warn (0, me, _("bad expression (missing right parenthesis): %s"), - expr); + m4_warn (0, me, _("missing right parenthesis: %s"), expr); break; case SYNTAX_ERROR: @@ -334,11 +335,11 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) break; case UNKNOWN_INPUT: - m4_warn (0, me, _("bad expression (bad input): %s"), expr); + m4_warn (0, me, _("bad input in expression: %s"), expr); break; case EXCESS_INPUT: - m4_warn (0, me, _("bad expression (excess input): %s"), expr); + m4_warn (0, me, _("excess input in expression: %s"), expr); break; case INVALID_OPERATOR: diff --git a/src/format.c b/src/format.c index 8b2b11ae..09cffa3c 100644 --- a/src/format.c +++ b/src/format.c @@ -27,24 +27,26 @@ same size; likewise for long and unsigned long. We do not yet handle long double or long long. */ -/* Parse STR as an integer, reporting warnings on behalf of ME. */ +/* Parse STR of length LEN as an integer, reporting warnings on behalf + of ME. */ static int -arg_int (const call_info *me, const char *str) +arg_int (const call_info *me, const char *str, size_t len) { char *endp; long value; /* TODO - also allow parsing `'a' or `"a' which results in the numeric value of 'a', as in printf(1). */ - if (*str == '\0') + if (!len) { m4_warn (0, me, _("empty string treated as 0")); return 0; } errno = 0; value = strtol (str, &endp, 10); - if (*endp != '\0') - m4_warn (0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (0, me, _("leading whitespace ignored")); else if (errno == ERANGE || (int) value != value) @@ -52,24 +54,26 @@ arg_int (const call_info *me, const char *str) return value; } -/* Parse STR as a long, reporting warnings on behalf of ME. */ +/* Parse STR of length LEN as a long, reporting warnings on behalf of + ME. */ static long -arg_long (const call_info *me, const char *str) +arg_long (const call_info *me, const char *str, size_t len) { char *endp; long value; /* TODO - also allow parsing `'a' or `"a' which results in the numeric value of 'a', as in printf(1). */ - if (*str == '\0') + if (!len) { m4_warn (0, me, _("empty string treated as 0")); return 0L; } errno = 0; value = strtol (str, &endp, 10); - if (*endp != '\0') - m4_warn (0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (0, me, _("leading whitespace ignored")); else if (errno == ERANGE) @@ -77,22 +81,35 @@ arg_long (const call_info *me, const char *str) return value; } -/* Parse STR as a double, reporting warnings on behalf of ME. */ +/* Check STR of length LEN for embedded NUL, reporting warnings on + behalf of ME. */ +static const char * +arg_string (const call_info *me, const char *str, size_t len) +{ + if (strlen (str) < len) + m4_warn (0, me, _("argument %s truncated"), + quotearg_style_mem (locale_quoting_style, str, len)); + return str; +} + +/* Parse STR of length LEN as a double, reporting warnings on behalf + of ME. */ static double -arg_double (const call_info *me, const char *str) +arg_double (const call_info *me, const char *str, size_t len) { char *endp; double value; - if (*str == '\0') + if (!len) { m4_warn (0, me, _("empty string treated as 0")); return 0.0; } errno = 0; value = strtod (str, &endp); - if (*endp != '\0') - m4_warn (0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (0, me, _("leading whitespace ignored")); else if (errno == ERANGE) @@ -101,16 +118,16 @@ arg_double (const call_info *me, const char *str) } #define ARG_INT(i, argc, argv) \ - ((argc <= ++i) ? 0 : arg_int (me, ARG (i))) + ((argc <= ++i) ? 0 : arg_int (me, ARG (i), ARG_LEN (i))) #define ARG_LONG(i, argc, argv) \ - ((argc <= ++i) ? 0L : arg_long (me, ARG (i))) + ((argc <= ++i) ? 0L : arg_long (me, ARG (i), ARG_LEN (i))) #define ARG_STR(i, argc, argv) \ - ((argc <= ++i) ? "" : ARG (i)) + ((argc <= ++i) ? "" : arg_string (me, ARG (i), ARG_LEN (i))) #define ARG_DOUBLE(i, argc, argv) \ - ((argc <= ++i) ? 0.0 : arg_double (me, ARG (i))) + ((argc <= ++i) ? 0.0 : arg_double (me, ARG (i), ARG_LEN (i))) /*------------------------------------------------------------------. diff --git a/src/freeze.c b/src/freeze.c index 5d4ac423..75e112b6 100644 --- a/src/freeze.c +++ b/src/freeze.c @@ -1,7 +1,7 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008 - Free Software Foundation, Inc. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008, + 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -343,8 +343,13 @@ reload_frozen_state (const char *name) case 'F': - /* Enter a macro having a builtin function as a definition. */ - + /* Enter a macro having a builtin function as a + definition. No builtin contains NUL in the name. */ + if (strlen (string[1]) < number[1]) + m4_error (EXIT_FAILURE, 0, NULL, _("\ +ill-formed frozen file, invalid builtin %s encountered"), + quotearg_style_mem (locale_quoting_style, string[1], + number[1])); bp = find_builtin_by_name (string[1]); define_builtin (string[0], number[0], bp, SYMBOL_PUSHDEF); break; @@ -370,7 +370,8 @@ process_file (const char *name) FILE *fp = m4_path_search (name, &full_name); if (fp == NULL) { - error (0, errno, "%s", name); + error (0, errno, "cannot open %s", + quotearg_style (locale_quoting_style, name)); /* Set the status to EXIT_FAILURE, even though we continue to process files after a missing file. */ retcode = EXIT_FAILURE; @@ -530,10 +531,11 @@ main (int argc, char *const *argv, char *const *envp) #endif case 'd': - debug_level = debug_decode (optarg); + debug_level = debug_decode (optarg, SIZE_MAX); if (debug_level < 0) { - error (0, 0, "bad debug flags: `%s'", optarg); + error (0, 0, "bad debug flags: %s", + quotearg_style (locale_quoting_style, optarg)); debug_level = 0; } break; @@ -584,7 +586,8 @@ main (int argc, char *const *argv, char *const *envp) /* Do the basic initializations. */ if (debugfile && !debug_set_output (NULL, debugfile)) - m4_error (0, errno, NULL, _("cannot set debug file `%s'"), debugfile); + m4_error (0, errno, NULL, _("cannot set debug file %s"), + quotearg_style (locale_quoting_style, debugfile)); input_init (); output_init (); @@ -602,7 +605,7 @@ main (int argc, char *const *argv, char *const *envp) if (interactive) { signal (SIGINT, SIG_IGN); - setbuf (stdout, (char *) NULL); + setbuf (stdout, NULL); } /* Handle deferred command line macro definitions. Must come after @@ -199,7 +199,7 @@ extern FILE *debug; #define DEBUG_TRACE_DEFAULT 0x007 void debug_init (void); -int debug_decode (const char *); +int debug_decode (const char *, size_t); void debug_flush_files (void); bool debug_set_output (const call_info *, const char *); void debug_message (const char *, ...) M4_GNUC_PRINTF (1, 2); @@ -160,7 +160,9 @@ m4_path_search (const char *file, char **result) if (fp != NULL) { if (debug_level & DEBUG_TRACE_PATH) - debug_message ("path search for `%s' found `%s'", file, name); + debug_message ("path search for %s found %s", + quotearg_style (locale_quoting_style, file), + quotearg_n_style (1, locale_quoting_style, name)); if (set_cloexec_flag (fileno (fp), true) != 0) m4_warn (errno, NULL, _("cannot protect input file across forks")); if (result) |