diff options
author | Eric Blake <ebb9@byu.net> | 2009-02-10 14:24:11 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-02-11 13:57:12 -0700 |
commit | 3e12364a5a32e5947b0c31a2ee6dc5351b7af5e6 (patch) | |
tree | 4ad1b5f91fa43ba300161f202805c39f4d518236 | |
parent | 5b4325856360a5d8836f13f17938b1acccd422cf (diff) | |
download | m4-3e12364a5a32e5947b0c31a2ee6dc5351b7af5e6.tar.gz |
Stage 28c: Warn on embedded NUL in remaining cases.
* m4/m4module.h (m4_debug_decode, m4_parse_truth_arg): Add
parameter.
* m4/macro.c (m4_macro_call): Improve diagnostic.
* modules/m4.c (defn): Likewise.
* m4/debug.c (m4_debug_decode): Handle embedded NUL.
* m4/utility.c (m4_parse_truth_arg): Likewise.
* modules/format.c (arg_int, arg_long, arg_double): Likewise.
(arg_string): New function.
(ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE): Update callers.
* src/main.c (main): Likewise.
* src/freeze.c (reload_frozen_state): Likewise.
* modules/gnu.c (debugmode, syncoutput): Likewise.
* tests/options.at (--regexp-syntax): Adjust test.
* tests/freeze.at (reloading nul): Likewise.
* tests/null.m4: Likewise.
* tests/null.out: Likewise.
* tests/null.err: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | m4/debug.c | 29 | ||||
-rw-r--r-- | m4/m4module.h | 4 | ||||
-rw-r--r-- | m4/macro.c | 7 | ||||
-rw-r--r-- | m4/utility.c | 15 | ||||
-rw-r--r-- | modules/format.c | 61 | ||||
-rw-r--r-- | modules/gnu.c | 12 | ||||
-rw-r--r-- | modules/m4.c | 8 | ||||
-rw-r--r-- | src/freeze.c | 33 | ||||
-rw-r--r-- | src/main.c | 26 | ||||
-rw-r--r-- | tests/freeze.at | 14 | ||||
-rw-r--r-- | tests/null.err | bin | 3237 -> 3634 bytes | |||
-rw-r--r-- | tests/null.m4 | bin | 7703 -> 7702 bytes | |||
-rw-r--r-- | tests/null.out | bin | 629 -> 632 bytes | |||
-rw-r--r-- | tests/options.at | 5 |
15 files changed, 170 insertions, 66 deletions
@@ -1,5 +1,27 @@ 2009-02-11 Eric Blake <ebb9@byu.net> + Stage 28c: Warn on embedded NUL in remaining cases. + Ensure all remaining warnings can handle embedded NUL. + Memory impact: none. + Speed impact: none noticed. + * m4/m4module.h (m4_debug_decode, m4_parse_truth_arg): Add + parameter. + * m4/macro.c (m4_macro_call): Improve diagnostic. + * modules/m4.c (defn): Likewise. + * m4/debug.c (m4_debug_decode): Handle embedded NUL. + * m4/utility.c (m4_parse_truth_arg): Likewise. + * modules/format.c (arg_int, arg_long, arg_double): Likewise. + (arg_string): New function. + (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE): Update callers. + * src/main.c (main): Likewise. + * src/freeze.c (reload_frozen_state): Likewise. + * modules/gnu.c (debugmode, syncoutput): Likewise. + * tests/options.at (--regexp-syntax): Adjust test. + * tests/freeze.at (reloading nul): Likewise. + * tests/null.m4: Likewise. + * tests/null.out: Likewise. + * tests/null.err: Likewise. + Stage 28b: Warn on embedded NUL in file arguments. Quote warning messages related to file and other NUL-terminated system commands. @@ -1,5 +1,5 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1991, 1992, 1993, 1994, 2006, 2007, 2008 Free + Copyright (C) 1991, 1992, 1993, 1994, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -30,22 +30,31 @@ static void set_debug_file (m4 *, const m4_call_info *, FILE *); -/* 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; or + SIZE_MAX if OPTS is NUL-terminated. If OPTS is NULL, use the + default flags. Used by main while processing option -d, and by the + builtin debugmode (). */ int -m4_debug_decode (m4 *context, const char *opts) +m4_debug_decode (m4 *context, const char *opts, size_t len) { int previous = context->debug_level; int level; char mode = '\0'; - if (opts == NULL || *opts == '\0') + if (!opts) + opts = ""; + if (len == SIZE_MAX) + len = strlen (opts); + if (!len) level = M4_DEBUG_TRACE_DEFAULT | previous; else { if (*opts == '-' || *opts == '+') - mode = *opts++; - for (level = 0; *opts; opts++) + { + len--; + mode = *opts++; + } + for (level = 0; len--; opts++) { switch (*opts) { @@ -101,9 +110,9 @@ m4_debug_decode (m4 *context, const char *opts) level |= M4_DEBUG_TRACE_DEREF; break; - case 'o': - level |= M4_DEBUG_TRACE_OUTPUT_DUMPDEF; - break; + case 'o': + level |= M4_DEBUG_TRACE_OUTPUT_DUMPDEF; + break; case 'V': level |= M4_DEBUG_TRACE_VERBOSE; diff --git a/m4/m4module.h b/m4/m4module.h index 84c203e5..07f8c1a5 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -172,7 +172,7 @@ extern bool m4_bad_argc (m4 *, size_t, const m4_call_info *, size_t, extern bool m4_numeric_arg (m4 *, const m4_call_info *, const char *, size_t, int *); extern bool m4_parse_truth_arg (m4 *, const m4_call_info *, const char *, - bool); + size_t, bool); extern m4_symbol *m4_symbol_value_lookup (m4 *, m4_macro_args *, size_t, bool); /* Error handling. */ @@ -421,7 +421,7 @@ enum { #define m4_is_debug_bit(C,B) ((m4_get_debug_level_opt (C) & (B)) != 0) -extern int m4_debug_decode (m4 *, const char *); +extern int m4_debug_decode (m4 *, const char *, size_t); extern bool m4_debug_set_output (m4 *, const m4_call_info *, const char *); extern void m4_debug_message_prefix (m4 *); @@ -1,6 +1,6 @@ /* GNU m4 -- A simple macro processor Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2001, 2006, 2007, - 2008 Free Software Foundation, Inc. + 2008, 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -675,8 +675,9 @@ m4_macro_call (m4 *context, m4_symbol_value *value, m4_obstack *expansion, argv); else if (m4_is_symbol_value_placeholder (value)) m4_warn (context, 0, argv->info, - _("builtin `%s' requested by frozen file not found"), - m4_get_symbol_value_placeholder (value)); + _("builtin %s requested by frozen file not found"), + quotearg_style (locale_quoting_style, + m4_get_symbol_value_placeholder (value))); else { assert (!"m4_macro_call"); diff --git a/m4/utility.c b/m4/utility.c index 6d19526f..215fabd3 100644 --- a/m4/utility.c +++ b/m4/utility.c @@ -102,15 +102,17 @@ m4_numeric_arg (m4 *context, const m4_call_info *caller, const char *arg, return true; } -/* Parse ARG as a truth value. If unrecognized, issue a warning on - behalf of CALLER and return PREVIOUS; otherwise return the parsed - value. */ +/* Parse ARG of length LEN as a truth value. If ARG is NUL, use "" + instead; otherwise, ARG must have a NUL-terminator (even if it also + has embedded NUL). If LEN is SIZE_MAX, use the string length of + ARG. If unrecognized, issue a warning on behalf of CALLER and + return PREVIOUS; otherwise return the parsed value. */ bool m4_parse_truth_arg (m4 *context, const m4_call_info *caller, const char *arg, - bool previous) + size_t len, bool previous) { /* 0, no, off, blank... */ - if (!arg || arg[0] == '\0' + if (!arg || len == 0 || arg[0] == '0' || arg[0] == 'n' || arg[0] == 'N' || ((arg[0] == 'o' || arg[0] == 'O') @@ -122,7 +124,8 @@ m4_parse_truth_arg (m4 *context, const m4_call_info *caller, const char *arg, || ((arg[0] == 'o' || arg[0] == 'O') && (arg[1] == 'n' || arg[1] == 'N'))) return true; - m4_warn (context, 0, caller, _("unknown directive `%s'"), arg); + m4_warn (context, 0, caller, _("unknown directive %s"), + quotearg_style_mem (locale_quoting_style, arg, len)); return previous; } diff --git a/modules/format.c b/modules/format.c index af983cdc..55333bef 100644 --- a/modules/format.c +++ b/modules/format.c @@ -1,6 +1,6 @@ /* GNU m4 -- A simple macro processor Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2001, 2006, 2007, - 2008 Free Software Foundation, Inc. + 2008, 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -26,24 +26,27 @@ 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 (struct m4 *context, const m4_call_info *me, const char *str) +arg_int (struct m4 *context, const m4_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 (context, 0, me, _("empty string treated as 0")); return 0; } errno = 0; value = strtol (str, &endp, 10); - if (*endp != '\0') - m4_warn (context, 0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (context, 0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (context, 0, me, _("leading whitespace ignored")); else if (errno == ERANGE || (int) value != value) @@ -51,24 +54,27 @@ arg_int (struct m4 *context, const m4_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 (struct m4 *context, const m4_call_info *me, const char *str) +arg_long (struct m4 *context, const m4_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 (context, 0, me, _("empty string treated as 0")); return 0L; } errno = 0; value = strtol (str, &endp, 10); - if (*endp != '\0') - m4_warn (context, 0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (context, 0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (context, 0, me, _("leading whitespace ignored")); else if (errno == ERANGE) @@ -76,22 +82,37 @@ arg_long (struct m4 *context, const m4_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 (struct m4 *context, const m4_call_info *me, const char *str, + size_t len) +{ + if (strlen (str) < len) + m4_warn (context, 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 (struct m4 *context, const m4_call_info *me, const char *str) +arg_double (struct m4 *context, const m4_call_info *me, const char *str, + size_t len) { char *endp; double value; - if (*str == '\0') + if (!len) { m4_warn (context, 0, me, _("empty string treated as 0")); return 0.0; } errno = 0; value = strtod (str, &endp); - if (*endp != '\0') - m4_warn (context, 0, me, _("non-numeric argument `%s'"), str); + if (endp - str != len) + m4_warn (context, 0, me, _("non-numeric argument %s"), + quotearg_style_mem (locale_quoting_style, str, len)); else if (isspace (to_uchar (*str))) m4_warn (context, 0, me, _("leading whitespace ignored")); else if (errno == ERANGE) @@ -100,16 +121,16 @@ arg_double (struct m4 *context, const m4_call_info *me, const char *str) } #define ARG_INT(i, argc, argv) \ - ((argc <= ++i) ? 0 : arg_int (context, me, M4ARG (i))) + ((argc <= ++i) ? 0 : arg_int (context, me, M4ARG (i), M4ARGLEN (i))) #define ARG_LONG(i, argc, argv) \ - ((argc <= ++i) ? 0L : arg_long (context, me, M4ARG (i))) + ((argc <= ++i) ? 0L : arg_long (context, me, M4ARG (i), M4ARGLEN (i))) #define ARG_STR(i, argc, argv) \ - ((argc <= ++i) ? "" : M4ARG (i)) + ((argc <= ++i) ? "" : arg_string (context, me, M4ARG (i), M4ARGLEN (i))) #define ARG_DOUBLE(i, argc, argv) \ - ((argc <= ++i) ? 0.0 : arg_double (context, me, M4ARG (i))) + ((argc <= ++i) ? 0.0 : arg_double (context, me, M4ARG (i), M4ARGLEN (i))) /* The main formatting function. Output is placed on the obstack OBS, diff --git a/modules/gnu.c b/modules/gnu.c index 69d938f1..f44f0ba4 100644 --- a/modules/gnu.c +++ b/modules/gnu.c @@ -625,11 +625,14 @@ M4BUILTIN_HANDLER (debuglen) **/ M4BUILTIN_HANDLER (debugmode) { + const char* mode = M4ARG (1); + size_t len = M4ARGLEN (1); if (argc == 1) m4_set_debug_level_opt (context, 0); - else if (m4_debug_decode (context, M4ARG (1)) < 0) - m4_error (context, 0, 0, m4_arg_info (argv), - _("bad debug flags: `%s'"), M4ARG (1)); + else if (m4_debug_decode (context, mode, len) < 0) + m4_warn (context, 0, m4_arg_info (argv), + _("bad debug flags: %s"), + quotearg_style_mem (locale_quoting_style, mode, len)); } @@ -997,6 +1000,7 @@ M4BUILTIN_HANDLER (m4symbols) M4BUILTIN_HANDLER (syncoutput) { bool value = m4_get_syncoutput_opt (context); - value = m4_parse_truth_arg (context, m4_arg_info (argv), M4ARG (1), value); + value = m4_parse_truth_arg (context, m4_arg_info (argv), M4ARG (1), + M4ARGLEN (1), value); m4_set_syncoutput_opt (context, value); } diff --git a/modules/m4.c b/modules/m4.c index 8ce419db..1ad1ce1c 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -395,8 +395,10 @@ M4BUILTIN_HANDLER (defn) m4_push_builtin (context, obs, m4_get_symbol_value (symbol)); else if (m4_is_symbol_placeholder (symbol)) m4_warn (context, 0, me, - _("%s: builtin `%s' requested by frozen file not found"), - M4ARG (i), m4_get_symbol_placeholder (symbol)); + _("%s: builtin %s requested by frozen file not found"), + quotearg_n_mem (2, M4ARG (i), M4ARGLEN (i)), + quotearg_style (locale_quoting_style, + m4_get_symbol_placeholder (symbol))); else { assert (!"Bad token data type in m4_defn"); @@ -947,7 +949,7 @@ M4BUILTIN_HANDLER (index) if (!m4_arg_empty (argv, 3) && !m4_numeric_arg (context, m4_arg_info (argv), M4ARG (3), M4ARGLEN (3), - &offset)) + &offset)) return; if (offset < 0) { diff --git a/src/freeze.c b/src/freeze.c index 0394d4c2..1a038424 100644 --- a/src/freeze.c +++ b/src/freeze.c @@ -1,6 +1,6 @@ /* GNU m4 -- A simple macro processor Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006, - 2007, 2008 Free Software Foundation, Inc. + 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU M4. @@ -634,7 +634,7 @@ ill-formed frozen file, version 2 directive `%c' encountered"), 'd'); GET_STRING (file, string[0], allocated[0], number[0], false); VALIDATE ('\n'); - if (m4_debug_decode (context, string[0]) < 0) + if (m4_debug_decode (context, string[0], number[0]) < 0) m4_error (context, EXIT_FAILURE, 0, NULL, _("unknown debug mode %s"), quotearg_style_mem (locale_quoting_style, string[0], @@ -696,8 +696,21 @@ ill-formed frozen file, version 2 directive `%c' encountered"), 'F'); m4_module *module = NULL; m4_symbol_value *token; + // Builtins cannot contain a NUL byte. + if (strlen (string[1]) < number[1]) + m4_error (context, EXIT_FAILURE, 0, NULL, _("\ +ill-formed frozen file, invalid builtin %s encountered"), + quotearg_style_mem (locale_quoting_style, string[1], + number[1])); if (number[2] > 0) - module = m4__module_find (string[2]); + { + if (strlen (string[2]) < number[2]) + m4_error (context, EXIT_FAILURE, 0, NULL, _("\ +ill-formed frozen file, invalid module %s encountered"), + quotearg_style_mem (locale_quoting_style, + string[2], number[2])); + module = m4__module_find (string[2]); + } token = m4_builtin_find_by_name (module, string[1]); if (token == NULL) @@ -732,6 +745,11 @@ ill-formed frozen file, version 2 directive `%c' encountered"), 'M'); GET_STRING (file, string[0], allocated[0], number[0], false); VALIDATE ('\n'); + if (strlen (string[0]) < number[0]) + m4_error (context, EXIT_FAILURE, 0, NULL, _("\ +ill-formed frozen file, invalid module %s encountered"), + quotearg_style_mem (locale_quoting_style, + string[0], number[0])); m4__module_open (context, string[0], NULL); break; @@ -940,7 +958,14 @@ ill-formed frozen file, version 2 directive `%c' encountered"), 'T'); token = (m4_symbol_value *) xzalloc (sizeof *token); if (number[2] > 0) - module = m4__module_find (string[2]); + { + if (strlen (string[2]) < number[2]) + m4_error (context, EXIT_FAILURE, 0, NULL, _("\ +ill-formed frozen file, invalid module %s encountered"), + quotearg_style_mem (locale_quoting_style, + string[2], number[2])); + module = m4__module_find (string[2]); + } m4_set_symbol_value_text (token, xmemdup0 (string[1], number[1]), number[1], 0); @@ -459,7 +459,7 @@ main (int argc, char *const *argv, char *const *envp) break; case 'E': - m4_debug_decode (context, "-d"); + m4_debug_decode (context, "-d", SIZE_MAX); if (m4_get_fatal_warnings_opt (context)) m4_set_warnings_exit_opt (context, true); else @@ -491,12 +491,13 @@ main (int argc, char *const *argv, char *const *envp) const char *dlerr = lt_dlerror (); if (dlerr == NULL) m4_error (context, EXIT_FAILURE, 0, NULL, - _("failed to add search directory `%s'"), - optarg); + _("failed to add search directory %s"), + quotearg_style (locale_quoting_style, optarg)); else m4_error (context, EXIT_FAILURE, 0, NULL, - _("failed to add search directory `%s': %s"), - optarg, dlerr); + _("failed to add search directory %s: %s"), + quotearg_style (locale_quoting_style, optarg), + dlerr); } break; @@ -533,8 +534,9 @@ main (int argc, char *const *argv, char *const *envp) have effect between files. */ if (seen_file || frozen_file_to_read) goto defer; - if (m4_debug_decode (context, optarg) < 0) - error (0, 0, _("bad debug flags: `%s'"), optarg); + if (m4_debug_decode (context, optarg, SIZE_MAX) < 0) + error (0, 0, _("bad debug flags: %s"), + quotearg_style (locale_quoting_style, optarg)); break; case 'e': @@ -689,8 +691,9 @@ main (int argc, char *const *argv, char *const *envp) break; case 'd': - if (m4_debug_decode (context, arg) < 0) - error (0, 0, _("bad debug flags: `%s'"), arg); + if (m4_debug_decode (context, arg, SIZE_MAX) < 0) + error (0, 0, _("bad debug flags: %s"), + quotearg_style (locale_quoting_style, arg)); break; case 'm': @@ -702,7 +705,8 @@ main (int argc, char *const *argv, char *const *envp) m4_set_regexp_syntax_opt (context, m4_regexp_syntax_encode (arg)); if (m4_get_regexp_syntax_opt (context) < 0) m4_error (context, EXIT_FAILURE, 0, NULL, - _("bad regexp syntax option: `%s'"), arg); + _("bad syntax-spec: %s"), + quotearg_style (locale_quoting_style, arg)); break; case 't': @@ -736,7 +740,7 @@ main (int argc, char *const *argv, char *const *envp) info.name_len = strlen (info.name); m4_set_syncoutput_opt (context, m4_parse_truth_arg (context, &info, arg, - previous)); + SIZE_MAX, previous)); } break; diff --git a/tests/freeze.at b/tests/freeze.at index 693ae543..338f6f5f 100644 --- a/tests/freeze.at +++ b/tests/freeze.at @@ -1,5 +1,5 @@ # Hand crafted tests for GNU M4. -*- Autotest -*- -# Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is part of GNU M4. # @@ -415,6 +415,18 @@ AT_CHECK_M4([-R bogus.m4f], [1], [], [[m4:bogus.m4f:4: bad syntax-spec `gnu\0' ]]) +dnl Reject escape sequences that expand to unexpected NUL +AT_DATA([bogus.m4f], +[[# bogus frozen file +V2 +F3,4 +len +len\0 +]]) +AT_CHECK_M4([-R bogus.m4f], [1], [], +[[m4:bogus.m4f:5: ill-formed frozen file, invalid builtin `len\0' encountered +]]) + AT_CLEANUP ]) diff --git a/tests/null.err b/tests/null.err Binary files differindex 01f2a8e7..38c610fe 100644 --- a/tests/null.err +++ b/tests/null.err diff --git a/tests/null.m4 b/tests/null.m4 Binary files differindex 60711449..0e13cb43 100644 --- a/tests/null.m4 +++ b/tests/null.m4 diff --git a/tests/null.out b/tests/null.out Binary files differindex 3859b239..993d9fe0 100644 --- a/tests/null.out +++ b/tests/null.out diff --git a/tests/options.at b/tests/options.at index 48e5b036..ad71f207 100644 --- a/tests/options.at +++ b/tests/options.at @@ -1,5 +1,6 @@ # Hand crafted tests for GNU M4. -*- Autotest -*- -# Copyright (C) 2001, 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2001, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This file is part of GNU M4. # @@ -722,7 +723,7 @@ AT_DATA([[in]], [[regexp(`(', `(') ]]) AT_CHECK_M4([--regexp-syntax=unknown in], [1], [], -[[m4: bad regexp syntax option: `unknown' +[[m4: bad syntax-spec: `unknown' ]]) AT_CHECK_M4([--regexp-syntax= in], [0], [[0 |