diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | doc/m4.texinfo | 10 | ||||
-rw-r--r-- | ltdl/m4/gnulib-cache.m4 | 4 | ||||
-rw-r--r-- | m4/macro.c | 3 | ||||
-rw-r--r-- | m4/system_.h | 4 | ||||
-rw-r--r-- | src/main.c | 33 | ||||
-rw-r--r-- | tests/options.at | 131 |
8 files changed, 194 insertions, 13 deletions
@@ -1,3 +1,16 @@ +2006-09-29 Eric Blake <ebb9@byu.net> + + * ltdl/m4/gnulib-cache.m4: Augment with gnulib-tool --import + xstrtol. + * m4/system_.h (N_): Define. + * src/main.c (main): Validate numeric arguments. + (size_opt): New function, idea borrowed from coreutils. + * m4/macro.c (expand_macro): -L0 implies no limit. + * doc/m4.texinfo (Invoking m4): Document this change. + * NEWS: Likewise. + * tests/options.at: (--arglength, --nesting-limit) + (--regexp-syntax): New tests of argument validation. + 2006-09-28 Eric Blake <ebb9@byu.net> * tests/options.at: Alphabetize the tests. @@ -96,7 +96,14 @@ promoted to 2.0. the prefix `m4' or `__'. * The `-l'/`--arglength' command line argument now affects dumpdef - output as well as trace output. + output as well as trace output. Also, it now performs argument + validation and accepts an optional multiplier suffix. + +* The `-L'/`--nesting-limit' command line option can now be set to 0 + to remove the default limit. However, it is still possible that heavily + nested input can cause abrupt program termination due to stack + overflow. Also, the option now performs argument validation and accepts + an optional multiplier suffix. * FIXME: `m4wrap' semantics need an update to FIFO. diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 1a99a0ae..563c6e86 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -609,7 +609,13 @@ loads the @samp{traditional} module in place of the @samp{gnu} module. @itemx --nesting-limit=@var{NUM} Artificially limit the nesting of macro calls to @var{NUM} levels, stopping program execution if this limit is ever exceeded. When not -specified, nesting is limited to 1024 levels. +specified, nesting is limited to 1024 levels. A value of zero means +unlimited; but then heavily nested code could potentially cause a stack +overflow. @var{NUM} can have an optional scaling suffix. +@comment FIXME - need a node on what scaling suffixes are supported (see +@comment [info coreutils 'block size'] for ideas), and need to consider +@comment whether builtins should also understand scaling suffixes: +@comment eval, mpeval, perhaps format The precise effect of this option might be more correctly associated with textual nesting than dynamic recursion. It has been useful @@ -695,10 +701,12 @@ future release. Restrict the size of the output generated by macro tracing or by @code{dumpdef} to @var{NUM} characters per string. If unspecified or zero, output is unlimited. @xref{Debug Levels}, for more details. +@var{NUM} can have an optional scaling suffix. @comment FIXME - should we add a debuglen macro that can alter this @comment setting on the fly? Also, should we add an option that @comment controls whether output strings are sanitized with escape @comment sequences, so that dumpdef is truly one line per macro? +@comment FIXME - see comment on --nesting-limit about NUM. @item -t @var{NAME} @itemx --trace=@var{NAME} diff --git a/ltdl/m4/gnulib-cache.m4 b/ltdl/m4/gnulib-cache.m4 index f7922b43..208e937b 100644 --- a/ltdl/m4/gnulib-cache.m4 +++ b/ltdl/m4/gnulib-cache.m4 @@ -15,11 +15,11 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strnlen strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf +# gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strnlen strtol unlocked-io verror xalloc xalloc-die xstrndup xstrtol xvasprintf # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([]) -gl_MODULES([assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strnlen strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf]) +gl_MODULES([assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strnlen strtol unlocked-io verror xalloc xalloc-die xstrndup xstrtol xvasprintf]) gl_AVOID([]) gl_SOURCE_BASE([gnu]) gl_M4_BASE([ltdl/m4]) @@ -238,7 +238,8 @@ expand_macro (m4 *context, const char *name, m4_symbol *symbol) value = m4_get_symbol_value (symbol); VALUE_PENDING (value)++; expansion_level++; - if (expansion_level > m4_get_nesting_limit_opt (context)) + if (m4_get_nesting_limit_opt (context) > 0 + && expansion_level > m4_get_nesting_limit_opt (context)) m4_error (context, EXIT_FAILURE, 0, _("\ recursion limit of %d exceeded, use -L<N> to change it"), m4_get_nesting_limit_opt (context)); diff --git a/m4/system_.h b/m4/system_.h index 13c204ad..4a3c0587 100644 --- a/m4/system_.h +++ b/m4/system_.h @@ -51,10 +51,12 @@ #ifndef _ # ifdef ENABLE_NLS # include <libintl.h> -# define _(Text) gettext ((Text)) +# define _(Text) gettext (Text) # else # define _(Text) (Text) # endif +# define gettext_noop(Text) Text +# define N_(Text) gettext_noop (Text) #endif @@ -25,6 +25,7 @@ #include "version-etc.h" #include "gnu/progname.h" #include "pathconf.h" +#include "xstrtol.h" #include <limits.h> @@ -236,6 +237,22 @@ enum interactive_choice INTERACTIVE_NO /* -b specified last */ }; +/* Convert OPT to size_t, reporting an error using MSGID if it does + not fit. */ +static size_t +size_opt (char const *opt, char const *msgid) +{ + unsigned long int size; + strtol_error status = xstrtoul (opt, NULL, 10, &size, "kKmMgGtTPEZY0"); + if (SIZE_MAX < size && status == LONGINT_OK) + status = LONGINT_OVERFLOW; + if (status != LONGINT_OK) + STRTOL_FATAL_ERROR (opt, _(msgid), status); + return size; +} + + +/* Main entry point. Parse arguments, load modules, then parse input. */ int main (int argc, char *const *argv, char *const *envp) { @@ -243,6 +260,7 @@ main (int argc, char *const *argv, char *const *envp) macro_definition *tail; macro_definition *defn; int optchar; /* option character */ + size_t size; /* for parsing numeric option arguments */ macro_definition *defines; FILE *fp; @@ -291,8 +309,8 @@ main (int argc, char *const *argv, char *const *envp) case 'H': case HASHSIZE_OPTION: - /* -H was supported in 1.4.x, but is a no-op now. FIXME - - remove support for -H after 2.0. */ + /* -H was supported in 1.4.x, but is a no-op now. FIXME - + remove support for -H after 2.0. */ error (0, 0, _("Warning: `%s' is deprecated"), optchar == 'H' ? "-H" : "--hashsize"); break; @@ -370,7 +388,8 @@ main (int argc, char *const *argv, char *const *envp) break; case 'L': - m4_set_nesting_limit_opt (context, atoi (optarg)); + size = size_opt (optarg, N_("nesting limit")); + m4_set_nesting_limit_opt (context, size); break; case 'M': @@ -424,15 +443,15 @@ main (int argc, char *const *argv, char *const *envp) case 'e': error (0, 0, _("Warning: `%s' is deprecated, use `%s' instead"), "-e", "-i"); - /* fall through */ + /* fall through */ case 'i': interactive = INTERACTIVE_YES; break; case 'l': - m4_set_max_debug_arg_length_opt (context, atoi (optarg)); - if (m4_get_max_debug_arg_length_opt (context) <= 0) - m4_set_max_debug_arg_length_opt (context, 0); + size = size_opt (optarg, + N_("debug argument length")); + m4_set_max_debug_arg_length_opt (context, size); break; case 'o': diff --git a/tests/options.at b/tests/options.at index 3820e44b..adbf3deb 100644 --- a/tests/options.at +++ b/tests/options.at @@ -133,6 +133,53 @@ m@&t@4_dnl() AT_CLEANUP +## --------- ## +## arglength ## +## --------- ## + +AT_SETUP([--arglength]) + +dnl Check for argument validation. + +AT_DATA([in], +[[define(`echo', `$@')dnl +traceon(`echo')dnl +echo(`long string') +]]) + +AT_CHECK_M4([--arglength=-1 in], [1], [], +[[m4: invalid debug argument length `-1' +]]) + +AT_CHECK_M4([--arglength oops in], [1], [], +[[m4: invalid debug argument length `oops' +]]) + +AT_CHECK_M4([-l 10oops in], [1], [], +[[m4: invalid character following debug argument length in `10oops' +]]) + +dnl MiB is the suffix to implict 1, resulting in 1048576 +AT_CHECK_M4([-lMiB in], [0], [[long string +]], [[m4trace: -1- echo(`long string') -> ``long string'' +]]) + +dnl this assumes size_t is no bigger than 64 bits +AT_CHECK_M4([-l 123456789012345678901234567890 in], [1], [], +[[m4: debug argument length `123456789012345678901234567890' too large +]]) + +AT_CHECK_M4([-l 3 in], [0], [[long string +]], [[m4trace: -1- echo(`lon...') -> ``lo...' +]]) + +AT_CHECK_M4([--arglength=3 -l0 in], [0], [[long string +]], [[m4trace: -1- echo(`long string') -> ``long string'' +]]) + +AT_CLEANUP + + ## ----------- ## ## debug flags ## ## ----------- ## @@ -294,6 +341,59 @@ OVERRIDE=It is changed. AT_CLEANUP +## ------------- ## +## nesting-limit ## +## ------------- ## + +AT_SETUP([--nesting-limit]) + +dnl Check for argument validation. + +AT_DATA([in], +[[define(`echo', `$@')dnl +echo(echo(echo(echo(`nested string')))) +echo(echo(echo(echo(echo(echo(echo(echo(echo(`nested string'))))))))) +]]) + +AT_CHECK_M4([--nesting-limit=-1 in], [1], [], +[[m4: invalid nesting limit `-1' +]]) + +AT_CHECK_M4([--nesting-limit oops in], [1], [], +[[m4: invalid nesting limit `oops' +]]) + +AT_CHECK_M4([-L 10oops in], [1], [], +[[m4: invalid character following nesting limit in `10oops' +]]) + +dnl MiB is the suffix to implict 1, resulting in 1048576 +AT_CHECK_M4([-LMiB in], [0], [[nested string +nested string +]]) + +dnl this assumes size_t is no bigger than 64 bits +AT_CHECK_M4([-L 123456789012345678901234567890 in], [1], [], +[[m4: nesting limit `123456789012345678901234567890' too large +]]) + +AT_CHECK_M4([-L 5 in], [1], [[nested string +]], +[[m4:in:3: recursion limit of 5 exceeded, use -L<N> to change it +]]) + +dnl per POSIX guidelines, this is a decimal number 10, not octal 8 +AT_CHECK_M4([-L 010 in], [0], [[nested string +nested string +]]) + +AT_CHECK_M4([--nesting-limit=3 -L0 in], [0], [[nested string +nested string +]]) + +AT_CLEANUP + + ## --------------- ## ## prepend-include ## ## --------------- ## @@ -338,6 +438,37 @@ in post/blah AT_CLEANUP +## ------------- ## +## regexp-syntax ## +## ------------- ## + +AT_SETUP([--regexp-syntax]) + +dnl test argument validation + +AT_DATA([[in]], [[regexp(`(', `(') +]]) + +AT_CHECK_M4([--regexp-syntax=unknown in], [1], [], +[[m4: bad regexp syntax option: `unknown' +]]) + +AT_CHECK_M4([--regexp-syntax '' in], [0], [[0 +]]) + +AT_CHECK_M4([-r EXTENDED in], [1], [[ +]], [[m4:in:1: regexp: bad regular expression `(': Unmatched ( or \( +]]) + +AT_CHECK_M4([-rgnu-m4 in], [0], [[0 +]]) + +AT_CHECK_M4([-r "gnu M4" in], [0], [[0 +]]) + +AT_CLEANUP + + ## ----- ## ## safer ## ## ----- ## |