[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
argv_ref patch 28: handle NUL in warning messages
From: |
Eric Blake |
Subject: |
argv_ref patch 28: handle NUL in warning messages |
Date: |
Wed, 11 Feb 2009 20:27:40 -0700 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081209 Thunderbird/2.0.0.19 Mnenhy/0.7.6.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I'm still going rather slowly at porting the argv_ref branch into master.
This patch rounds out the handling of embedded NUL in all of the builtins
(in most of these cases, the presence of an embedded NUL is a user bug,
but the warning message should not be truncated at the NUL). I still need
to beef up the NEWS and manual about the fact that embedded NUL support is
now present in m4. On the master branch, I subdivided the patch into
three roughly equal parts. Also, working on this patch uncovered a hole
in branch-1.6 handling of warning on popdef(undef), which I patched
earlier today. No real change in memory usage or speed.
Stage 28: Allow embedded NUL in warning messages.
Issue graceful error messages for a variety of places where
embedded NUL is otherwise unhandled. For example, numeric parsing
rejects embedded NUL, while file-related commands warn about
truncation at NUL, and frozen files detect unexpected NUL.
Memory impact: none.
Speed impact: none noticed.
* src/m4.h (debug_decode): Add argument.
* src/m4.c (main): Adjust caller.
* src/format.c (arg_int, arg_long, arg_double): Likewise.
(arg_string): New function.
(ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE): Support embedded NUL.
* src/freeze.c (reload_frozen_state): Likewise.
* src/debug.c (debug_decode): Likewise.
* src/builtin.c (numeric_arg): Add argument.
(m4_syscmd, m4_esyscmd, m4_eval, m4_incr, m4_decr, m4_divert)
(m4_undivert, include, mkstemp_helper, m4_m4exit, m4_debugmode)
(m4_debugfile, m4_index, m4_substr): Detect embedded NUL.
(m4_defn, m4_maketemp, m4_placeholder): Improve warning message.
* src/path.c (m4_path_search): Likewise.
* doc/m4.texinfo (Syntax, Mkstemp, Using frozen files): Adjust
tests.
* examples/null.m4: Likewise.
* examples/null.out: Likewise.
* examples/null.err: Likewise.
- --
Don't work too hard, make some time for fun as well!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkmTlywACgkQ84KuGfSFAYBadwCgnNHWJdUxeGRE+uGPZxa9VGTk
GngAoK0Zk3cA5jlccjK3ixr4HPpuX9/i
=J55f
-----END PGP SIGNATURE-----
From 185b10ba33786707f6478b8315e9527151f60902 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 5 Feb 2009 07:47:32 -0700
Subject: [PATCH 1/3] Stage 28a: Warn on embedded NUL in numeric arguments.
* m4/m4module.h (m4_numeric_arg): Adjust prototype.
* m4/utility.c (m4_numeric_arg): Add parameter.
* modules/gnu.c (debuglen): Adjust callers.
* modules/m4.c (incr, decr, divert, undivert, m4exit, substr)
(index): Likewise.
* modules/evalparse.c (m4_evaluate): Likewise.
* modules/stdlib.c (setenv, getpwuid, srand): Likewise.
* modules/time.c (ctime, gmtime, localtime, mktime, strftime):
Likewise.
* doc/m4.texinfo (Changesyntax): Fix typo.
* tests/others.at (nul character): Adjust test.
* tests/null.m4: Likewise.
* tests/null.out: Likewise.
* tests/null.err: Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 22 ++++++++++++++++++++++
doc/m4.texinfo | 2 +-
m4/m4module.h | 4 ++--
m4/utility.c | 24 +++++++++++++++---------
modules/evalparse.c | 7 ++++---
modules/gnu.c | 7 ++++---
modules/m4.c | 29 +++++++++++++++++++----------
modules/stdlib.c | 13 ++++++++-----
modules/time.c | 31 ++++++++++++++++++-------------
tests/null.err | 43 +++++++++++++++++++++++++++++++------------
tests/null.m4 | 43 ++++++++++++++++++++++++++++++++++---------
tests/null.out | 2 +-
tests/others.at | 8 ++++++--
13 files changed, 165 insertions(+), 70 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index acbdeec..def85f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
2009-02-11 Eric Blake <address@hidden>
+ Stage 28a: Warn on embedded NUL in numeric arguments.
+ Quote warning messages related to numeric parsing in order to
+ handle embedded NUL.
+ Memory impact: none.
+ Speed impact: none noticed.
+ * m4/m4module.h (m4_numeric_arg): Adjust prototype.
+ * m4/utility.c (m4_numeric_arg): Add parameter.
+ * modules/gnu.c (debuglen): Adjust callers.
+ * modules/m4.c (incr, decr, divert, undivert, m4exit, substr)
+ (index): Likewise.
+ * modules/evalparse.c (m4_evaluate): Likewise.
+ * modules/stdlib.c (setenv, getpwuid, srand): Likewise.
+ * modules/time.c (ctime, gmtime, localtime, mktime, strftime):
+ Likewise.
+ * doc/m4.texinfo (Changesyntax): Fix typo.
+ * tests/others.at (nul character): Adjust test.
+ * tests/null.m4: Likewise.
+ * tests/null.out: Likewise.
+ * tests/null.err: Likewise.
+
+2009-02-11 Eric Blake <address@hidden>
+
Avoid regression in popdef(undef).
* doc/m4.texinfo (Trace): Enhance test, to cover regression
recently fixed on the branch.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index f972b48..62fed45 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -5751,7 +5751,7 @@ Changesyntax
@example
changesyntax(`(@{<', `)@}>', `,;:', `O(,)')
@result{}
address@hidden; 2 : 8>
address@hidden; 2: 8>
@result{}00001111
@end example
diff --git a/m4/m4module.h b/m4/m4module.h
index d5ad513..84c203e 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1999, 2000, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -170,7 +170,7 @@ struct m4_string_pair
extern bool m4_bad_argc (m4 *, size_t, const m4_call_info *, size_t,
size_t, bool);
extern bool m4_numeric_arg (m4 *, const m4_call_info *, const char *,
- int *);
+ size_t, int *);
extern bool m4_parse_truth_arg (m4 *, const m4_call_info *, const char *,
bool);
extern m4_symbol *m4_symbol_value_lookup (m4 *, m4_macro_args *, size_t, bool);
diff --git a/m4/utility.c b/m4/utility.c
index 31c1705..6d19526 100644
--- a/m4/utility.c
+++ b/m4/utility.c
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2003,
- 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -68,30 +68,36 @@ skip_space (m4 *context, const char *arg)
return arg;
}
-/* The function m4_numeric_arg () converts ARG to an int pointed to by
- VALUEP. If the conversion fails, print error message for CALLER.
- Return true iff conversion succeeds. */
+/* The function m4_numeric_arg () converts ARG of length LEN to an int
+ pointed to by VALUEP. If the conversion fails, print error message
+ for CALLER. Return true iff conversion succeeds. */
/* FIXME: Convert this to use gnulib's xstrtoimax, xstrtoumax.
Otherwise, we are arbitrarily limiting integer values. */
bool
m4_numeric_arg (m4 *context, const m4_call_info *caller, const char *arg,
- int *valuep)
+ size_t len, int *valuep)
{
char *endp;
- if (*arg == '\0')
+ if (!len)
{
*valuep = 0;
m4_warn (context, 0, caller, _("empty string treated as 0"));
}
else
{
- *valuep = strtol (skip_space (context, arg), &endp, 10);
- if (*skip_space (context, endp) != 0)
+ const char *str = skip_space (context, arg);
+ *valuep = strtol (str, &endp, 10);
+ if (endp - arg != len)
{
- m4_warn (context, 0, caller, _("non-numeric argument `%s'"), arg);
+ m4_warn (context, 0, caller, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, arg, len));
return false;
}
+ if (str != arg)
+ m4_warn (context, 0, caller, _("leading whitespace ignored"));
+ else if (errno == ERANGE)
+ m4_warn (context, 0, caller, _("numeric overflow detected"));
}
return true;
}
diff --git a/modules/evalparse.c b/modules/evalparse.c
index ac30cfe..87a318e 100644
--- a/modules/evalparse.c
+++ b/modules/evalparse.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.
@@ -901,7 +901,7 @@ m4_evaluate (m4 *context, m4_obstack *obs, size_t argc,
m4_macro_args *argv)
eval_error err = NO_ERROR;
if (!m4_arg_empty (argv, 2)
- && !m4_numeric_arg (context, me, M4ARG (2), &radix))
+ && !m4_numeric_arg (context, me, M4ARG (2), M4ARGLEN (2), &radix))
return;
if (radix < 1 || radix > 36)
@@ -910,7 +910,8 @@ m4_evaluate (m4 *context, m4_obstack *obs, size_t argc,
m4_macro_args *argv)
return;
}
- if (argc >= 4 && !m4_numeric_arg (context, me, M4ARG (3), &min))
+ if (argc >= 4 && !m4_numeric_arg (context, me, M4ARG (3), M4ARGLEN (3),
+ &min))
return;
if (min < 0)
diff --git a/modules/gnu.c b/modules/gnu.c
index 8ad1722..ce14532 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 2000, 2004, 2005, 2006, 2007, 2008 Free Software
- Foundation, Inc.
+ Copyright (C) 2000, 2004, 2005, 2006, 2007, 2008, 2009 Free
+ Software Foundation, Inc.
This file is part of GNU M4.
@@ -599,7 +599,8 @@ M4BUILTIN_HANDLER (debuglen)
{
int i;
size_t s;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &i))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &i))
return;
/* FIXME - make m4_numeric_arg more powerful - we want to accept
suffixes, and limit the result to size_t. */
diff --git a/modules/m4.c b/modules/m4.c
index 177590d..44e8a0a 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -536,7 +536,8 @@ M4BUILTIN_HANDLER (incr)
{
int value;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &value))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &value))
return;
m4_shipout_int (obs, value + 1);
@@ -546,7 +547,8 @@ M4BUILTIN_HANDLER (decr)
{
int value;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &value))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &value))
return;
m4_shipout_int (obs, value - 1);
@@ -563,7 +565,7 @@ M4BUILTIN_HANDLER (divert)
int i = 0;
if (argc >= 2 && !m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1),
- &i))
+ M4ARGLEN (1), &i))
return;
m4_make_diversion (context, i);
m4_divert_text (context, NULL, M4ARG (2), M4ARGLEN (2),
@@ -592,12 +594,17 @@ M4BUILTIN_HANDLER (undivert)
for (i = 1; i < argc; i++)
{
const char *str = M4ARG (i);
+ size_t len = M4ARGLEN (i);
char *endp;
int diversion = strtol (str, &endp, 10);
- if (*endp == '\0' && !isspace ((unsigned char) *str))
+ if (endp - str == len && !isspace ((unsigned char) *str))
m4_insert_diversion (context, diversion);
else if (m4_get_posixly_correct_opt (context))
- m4_numeric_arg (context, me, str, &diversion);
+ m4_warn (context, 0, me, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
+ else if (strlen (str) != len)
+ m4_warn (context, 0, me, _("invalid file name %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else
{
FILE *fp = m4_path_search (context, str, NULL);
@@ -609,7 +616,7 @@ M4BUILTIN_HANDLER (undivert)
quotearg_style (locale_quoting_style, str));
}
else
- m4_error (context, 0, errno, me, _("cannot undivert `%s'"),
+ m4_error (context, 0, errno, me, _("cannot undivert %s"),
quotearg_style (locale_quoting_style, str));
}
}
@@ -824,7 +831,8 @@ M4BUILTIN_HANDLER (m4exit)
int exit_code = EXIT_SUCCESS;
/* Warn on bad arguments, but still exit. */
- if (argc >= 2 && !m4_numeric_arg (context, me, M4ARG (1), &exit_code))
+ if (argc >= 2 && !m4_numeric_arg (context, me, M4ARG (1), M4ARGLEN (1),
+ &exit_code))
exit_code = EXIT_FAILURE;
if (exit_code < 0 || exit_code > 255)
{
@@ -919,7 +927,8 @@ M4BUILTIN_HANDLER (index)
int retval = -1;
if (!m4_arg_empty (argv, 3) && !m4_numeric_arg (context, m4_arg_info (argv),
- M4ARG (3), &offset))
+ M4ARG (3), M4ARGLEN (3),
+ &offset))
return;
if (offset < 0)
{
@@ -967,7 +976,7 @@ M4BUILTIN_HANDLER (substr)
length = M4ARGLEN (1);
if (!m4_arg_empty (argv, 2)
- && !m4_numeric_arg (context, me, M4ARG (2), &start))
+ && !m4_numeric_arg (context, me, M4ARG (2), M4ARGLEN (2), &start))
return;
if (start < 0)
start += length;
@@ -976,7 +985,7 @@ M4BUILTIN_HANDLER (substr)
end = length;
else
{
- if (!m4_numeric_arg (context, me, M4ARG (3), &end))
+ if (!m4_numeric_arg (context, me, M4ARG (3), M4ARGLEN (3), &end))
return;
if (end < 0)
end += length;
diff --git a/modules/stdlib.c b/modules/stdlib.c
index b60e977..3fce71f 100644
--- a/modules/stdlib.c
+++ b/modules/stdlib.c
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1999, 2000, 2001, 2006, 2007, 2008 Free Software
- Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2006, 2007, 2008, 2009 Free
+ Software Foundation, Inc.
This file is part of GNU M4.
@@ -108,7 +108,8 @@ M4BUILTIN_HANDLER (setenv)
int overwrite = 1;
if (argc >= 4)
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (3), &overwrite))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (3), M4ARGLEN (3),
+ &overwrite))
return;
#if HAVE_SETENV
@@ -206,7 +207,8 @@ M4BUILTIN_HANDLER (getpwuid)
struct passwd *pw;
int uid;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &uid))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &uid))
return;
pw = getpwuid (uid);
@@ -261,7 +263,8 @@ M4BUILTIN_HANDLER (srand)
seed = time (0L) * getpid ();
else
{
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &seed))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1),
+ M4ARGLEN (1), &seed))
return;
}
diff --git a/modules/time.c b/modules/time.c
index a922a67..ee193a7 100644
--- a/modules/time.c
+++ b/modules/time.c
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1999, 2000, 2001, 2006, 2007, 2008 Free Software
- Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2006, 2007, 2008, 2009 Free
+ Software Foundation, Inc.
This file is part of GNU M4.
@@ -104,7 +104,8 @@ M4BUILTIN_HANDLER (ctime)
if (argc == 2)
{
- m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &i);
+ m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &i);
t = i;
}
else
@@ -152,7 +153,8 @@ M4BUILTIN_HANDLER (gmtime)
time_t t;
int i;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &i))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &i))
return;
t = i;
@@ -167,7 +169,8 @@ M4BUILTIN_HANDLER (localtime)
time_t t;
int i;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), &i))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
+ &i))
return;
t = i;
@@ -184,19 +187,20 @@ M4BUILTIN_HANDLER (mktime)
struct tm tm;
time_t t;
- if (!m4_numeric_arg (context, me, M4ARG (1), &tm.tm_sec))
+ if (!m4_numeric_arg (context, me, M4ARG (1), M4ARGLEN (1), &tm.tm_sec))
return;
- if (!m4_numeric_arg (context, me, M4ARG (2), &tm.tm_min))
+ if (!m4_numeric_arg (context, me, M4ARG (2), M4ARGLEN (2), &tm.tm_min))
return;
- if (!m4_numeric_arg (context, me, M4ARG (3), &tm.tm_hour))
+ if (!m4_numeric_arg (context, me, M4ARG (3), M4ARGLEN (3), &tm.tm_hour))
return;
- if (!m4_numeric_arg (context, me, M4ARG (4), &tm.tm_mday))
+ if (!m4_numeric_arg (context, me, M4ARG (4), M4ARGLEN (4), &tm.tm_mday))
return;
- if (!m4_numeric_arg (context, me, M4ARG (5), &tm.tm_mon))
+ if (!m4_numeric_arg (context, me, M4ARG (5), M4ARGLEN (5), &tm.tm_mon))
return;
- if (!m4_numeric_arg (context, me, M4ARG (6), &tm.tm_year))
+ if (!m4_numeric_arg (context, me, M4ARG (6), M4ARGLEN (6), &tm.tm_year))
return;
- if (M4ARG (7) && !m4_numeric_arg (context, me, M4ARG (7), &tm.tm_isdst))
+ if (M4ARG (7) && !m4_numeric_arg (context, me, M4ARG (7), M4ARGLEN (7),
+ &tm.tm_isdst))
return;
t = mktime (&tm);
@@ -216,7 +220,8 @@ M4BUILTIN_HANDLER (strftime)
char *buf;
int l;
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (2), &l))
+ if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (2), M4ARGLEN (2),
+ &l))
return;
t = l;
diff --git a/tests/null.err b/tests/null.err
index 7b9f798..edad891 100644
--- a/tests/null.err
+++ b/tests/null.err
@@ -7,10 +7,16 @@ changeresyntax:
m4:null.m4:39: Warning: changeresyntax: bad syntax-spec: `\0'
changesyntax:
m4:null.m4:48: Warning: changesyntax: undefined syntax code: `\0'
+debuglen:
+m4:null.m4:53: Warning: debuglen: non-numeric argument `1\0001'
+decr:
+m4:null.m4:57: Warning: decr: non-numeric argument `1\0001'
defn:
-m4:null.m4:57: Warning: defn: undefined macro `\0-\0'
+m4:null.m4:62: Warning: defn: undefined macro `\0-\0'
+divert:
+m4:null.m4:69: Warning: divert: non-numeric argument `1\0001'
dumpdef:
-m4:null.m4:70: Warning: dumpdef: undefined macro `\0-\0'
+m4:null.m4:77: Warning: dumpdef: undefined macro `\0-\0'
: `empty'
-: `dash'
- -: ``$0': $1'
@@ -18,21 +24,34 @@ m4:null.m4:70: Warning: dumpdef: undefined macro `\0-\0'
--: `dashes'
body: `- -'
errprint: - - - -
+eval:
+m4:null.m4:90: Warning: eval: bad input: `1\0+1'
+m4:null.m4:92: Warning: eval: non-numeric argument `2\0002'
+m4:null.m4:94: Warning: eval: non-numeric argument `1\0001'
format:
-m4:null.m4:87: Warning: format: unrecognized specifier in `%\0%'
-m4:null.m4:87: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:99: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:99: Warning: format: unrecognized specifier in `%\0%'
+incr:
+m4:null.m4:110: Warning: incr: non-numeric argument `1\0001'
+index:
+m4:null.m4:116: Warning: index: non-numeric argument `1\0001'
indir:
-m4:null.m4:104: Warning: indir: undefined macro `\0-\0'
-m4:null.m4:106: Warning: \0\0%%: extra arguments ignored: 1 > 0
+m4:null.m4:121: Warning: indir: undefined macro `\0-\0'
+m4:null.m4:123: Warning: \0\0%%: extra arguments ignored: 1 > 0
patsubst:
-m4:null.m4:124: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:134: Warning: patsubst: bad syntax-spec: `\0'
+m4:null.m4:141: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:151: Warning: patsubst: bad syntax-spec: `\0'
regexp:
-m4:null.m4:146: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:156: Warning: regexp: bad syntax-spec: `\0'
+m4:null.m4:163: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:173: Warning: regexp: bad syntax-spec: `\0'
renamesyms:
-m4:null.m4:161: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:167: Warning: renamesyms: bad syntax-spec: `\0'
+m4:null.m4:178: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:184: Warning: renamesyms: bad syntax-spec: `\0'
+substr:
+m4:null.m4:192: Warning: substr: non-numeric argument `1\0001'
+m4:null.m4:194: Warning: substr: non-numeric argument `1\0001'
traceon:
m4trace: -1- - -(`- -') -> `strange: - -'
m4trace: -1- body -> ` - '
+undivert:
+m4:null.m4:218: Warning: undivert: invalid file name `1\0001'
diff --git a/tests/null.m4 b/tests/null.m4
index f7a1587..3d57806 100644
--- a/tests/null.m4
+++ b/tests/null.m4
@@ -1,7 +1,7 @@
dnl Use `m4 -DNUL to print a NUL byte surrounded in [], then exit
ifdef(`NUL', `[ ]m4exit`'')dnl
# This file tests m4 behavior on NUL bytes.
-dnl Use `m4 -Dm4exit' to test rest of file. NUL not a number, needs to warn
+dnl Use `m4 -Dm4exit' to test rest of file.
m4exit(`2 2')dnl
dnl Raw pass-through:
raw: - -
@@ -48,8 +48,13 @@ errprint(`changesyntax:
')changesyntax( )dnl
dnl Ignored by changesyntax: TODO - support ignored category?
dnl Warning from debugfile: not tested yet. No file name includes NUL, needs
to warn
+dnl Warning from debuglen:
+errprint(`debuglen:
+')debuglen(`1 1')dnl
dnl Warning from debugmode: not tested yet. NUL not a valid mode, needs to warn
-dnl Warning from decr: not tested yet. NUL not a number, needs to warn
+dnl Warning from decr:
+errprint(`decr:
+')decr(`1 1')dnl
dnl Definition of define:
`define:' define(`body', `- -')body
dnl Undefined argument of defn:
@@ -59,7 +64,9 @@ dnl Defined macro name in defn:
`defn:' defn(`- -')dnl
dnl Macro contents in defn:
defn(`body')
-dnl Argument to divert: not tested yet. NUL not a number, needs to warn
+dnl Argument to divert:
+errprint(`divert:
+')divert(`1 1')dnl
dnl Passed through diversion by divert:
divert(`1')`divert:' - -
divert`'undivert(`1')dnl
@@ -78,8 +85,13 @@ errprint(`errprint:' - -, `- -
dnl Passed to esyscmd: not tested yet. NUL truncates string, needs to warn
dnl Generated from esyscmd:
`esyscmd:' esyscmd(__program__` -DNUL '__file__) sysval
-dnl First argument of eval: not tested yet. NUL not a number, needs to warn
-dnl Other arguments of eval: not tested yet. NUL not a number, needs to warn
+dnl First argument of eval:
+errprint(`eval:
+')eval(`1 +1')dnl
+dnl Second argument of eval:
+eval(`1', `2 2')dnl
+dnl Third argument of eval:
+eval(`1', `10', `1 1')dnl
dnl First argument to format:
`format:' format(`%s %s', `-', `-')dnl
dnl Invalid specifier in format:
@@ -93,10 +105,15 @@ dnl Macro name in ifdef, passed through ifdef:
dnl Compared in ifelse, passed through ifelse:
`ifelse:' ifelse(`-', `- -', `oops', `- -', - -, `yes: - -')
dnl Warning from include: not tested yet. No file name includes NUL, needs to
warn
-dnl Warning from incr: not tested yet. NUL not a number, needs to warn
+dnl Warning from incr:
+errprint(`incr:
+')incr(`1 1')dnl
dnl Passed through index:
`index:' index(`a b', `b') index(`-', ` ') index(` ', `-')dnl
index(` -', ` -')
+dnl Third argument of index:
+errprint(`index:
+')index(`aba', `a', `1 1')dnl
dnl Defined first argument of indir:
`indir:' indir(`- -', 1 1)dnl
dnl Undefined first argument of indir:
@@ -169,8 +186,14 @@ dnl Passed through shift:
`shift:' shift(`hi', `- -', - -)
dnl Warning from sinclude: not tested yet. No file name includes NUL, needs to
warn
dnl First argument of substr:
-`substr:' substr(`-- --', `1', `3')
-dnl Other arguments of substr: not tested yet. NUL not a number, needs to warn.
+`substr:' substr(`-- --', `1', `3')dnl
+dnl Second argument of substr:
+errprint(`substr:
+')substr(`abc', `1 1')dnl
+dnl Third argument of substr:
+substr(`abc', `1', `1 1')dnl
+dnl Fourth argument of substr:
+ substr(`abc', `1', `1', `1 1')
dnl Warning from syncoutput: not tested yet. No mode contains NUL, needs to
warn
dnl Passed to syscmd: not tested yet. NUL truncates string, needs to warn
dnl Sysval takes no arguments, and never produces NUL.
@@ -190,5 +213,7 @@ dnl Character ranges of translit:
dnl Defined argument of undefine:
`undefine:' undefine(`- -')ifdef(`- -', `oops', `ok')
dnl Undefined argument of undefine: not tested yet. Should it warn?
-dnl Warning from undivert: not tested yet. No file name or number includes
NUL, needs to warn
+dnl Warning from undivert:
+errprint(`undivert:
+')undivert(`1 1')dnl
dnl other modules need to be tested independently
diff --git a/tests/null.out b/tests/null.out
index 97f80dd..cfb78c0 100644
--- a/tests/null.out
+++ b/tests/null.out
@@ -24,7 +24,7 @@ pushdef: ok -
regexp: 2 ! 1 - - -
renamesyms: 0 0
shift: - -,- -
-substr: - -
+substr: - - a1 1c
traceon: strange: - - -
translit: - - . . cd
undefine: ok
diff --git a/tests/others.at b/tests/others.at
index 6776ee3..3f12351 100644
--- a/tests/others.at
+++ b/tests/others.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.
#
@@ -432,8 +433,11 @@ dnl all but m4exit
AT_CHECK_M4([-Dm4exit -I "$abs_srcdir" null.m4], [0], [expout], [experr])
dnl just m4exit
-AT_CHECK_M4(["$abs_srcdir/null.m4"], [2],
+AT_CHECK_M4(["$abs_srcdir/null.m4"], [1],
[[# This file tests m4 behavior on NUL bytes.
+]], [stderr])
+AT_CHECK([sed "s|$abs_srcdir/||" stderr], [0],
+[[m4:null.m4:5: Warning: m4exit: non-numeric argument `2\0002'
]])
AT_CLEANUP
--
1.6.1.2
From 5b4325856360a5d8836f13f17938b1acccd422cf Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Sat, 7 Feb 2009 18:50:21 -0700
Subject: [PATCH 2/3] Stage 28b: Warn on embedded NUL in file arguments.
* m4/path.c (m4_path_search): Quote file names in message.
* modules/m4.c (syscmd, include, m4_make_temp): Handle embedded
NUL.
* modules/gnu.c (debugfile, esyscmd): Likewise.
* tests/others.at (nul character): Adjust test.
* tests/builtins.at (mkdtemp, mkstemp): Likewise.
* tests/null.m4: Likewise.
* tests/null.out: Likewise.
* tests/null.err: Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 15 +++++++++++
m4/path.c | 7 +++--
modules/gnu.c | 26 +++++++++++++++----
modules/m4.c | 35 +++++++++++++++++++++------
tests/builtins.at | 10 ++++----
tests/null.err | 68 +++++++++++++++++++++++++++++++++++------------------
tests/null.m4 | 34 +++++++++++++++++++-------
tests/null.out | 5 +++-
tests/others.at | 2 +-
9 files changed, 146 insertions(+), 56 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index def85f5..29fc9ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2009-02-11 Eric Blake <address@hidden>
+ Stage 28b: Warn on embedded NUL in file arguments.
+ Quote warning messages related to file and other NUL-terminated
+ system commands.
+ Memory impact: none.
+ Speed impact: none noticed.
+ * m4/path.c (m4_path_search): Quote file names in message.
+ * modules/m4.c (syscmd, include, m4_make_temp): Handle embedded
+ NUL.
+ * modules/gnu.c (debugfile, esyscmd): Likewise.
+ * tests/others.at (nul character): Adjust test.
+ * tests/builtins.at (mkdtemp, mkstemp): Likewise.
+ * tests/null.m4: Likewise.
+ * tests/null.out: Likewise.
+ * tests/null.err: Likewise.
+
Stage 28a: Warn on embedded NUL in numeric arguments.
Quote warning messages related to numeric parsing in order to
handle embedded NUL.
diff --git a/m4/path.c b/m4/path.c
index bf15193..c83aa21 100644
--- a/m4/path.c
+++ b/m4/path.c
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1998, 2004, 2006, 2007,
- 2008 Free Software Foundation, Inc.
+ 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -198,8 +198,9 @@ m4_path_search (m4 *context, const char *file, char
**expanded_name)
if (fp != NULL)
{
m4_debug_message (context, M4_DEBUG_TRACE_PATH,
- _("path search for `%s' found `%s'"),
- file, name);
+ _("path search for %s found %s"),
+ quotearg_style (locale_quoting_style, file),
+ quotearg_n_style (1, locale_quoting_style, name));
if (expanded_name != NULL)
*expanded_name = name;
else
diff --git a/modules/gnu.c b/modules/gnu.c
index ce14532..69d938f 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -583,9 +583,17 @@ M4BUILTIN_HANDLER (debugfile)
m4_debug_set_output (context, me, NULL);
else if (m4_get_safer_opt (context) && !m4_arg_empty (argv, 1))
m4_error (context, 0, 0, me, _("disabled by --safer"));
- else if (!m4_debug_set_output (context, me, M4ARG (1)))
- m4_error (context, 0, errno, me, _("cannot set debug file %s"),
- quotearg_style (locale_quoting_style, M4ARG (1)));
+ else
+ {
+ const char *str = M4ARG (1);
+ size_t len = M4ARGLEN (1);
+ if (strlen (str) < len)
+ m4_warn (context, 0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, str, len));
+ if (!m4_debug_set_output (context, me, str))
+ m4_warn (context, errno, me, _("cannot set debug file %s"),
+ quotearg_style (locale_quoting_style, str));
+ }
}
@@ -635,6 +643,8 @@ M4BUILTIN_HANDLER (debugmode)
M4BUILTIN_HANDLER (esyscmd)
{
const m4_call_info *me = m4_arg_info (argv);
+ const char *cmd = M4ARG (1);
+ size_t len = M4ARGLEN (1);
M4_MODULE_IMPORT (m4, m4_set_sysval);
M4_MODULE_IMPORT (m4, m4_sysval_flush);
@@ -648,9 +658,12 @@ M4BUILTIN_HANDLER (esyscmd)
m4_error (context, 0, 0, me, _("disabled by --safer"));
return;
}
+ if (strlen (cmd) != len)
+ m4_warn (context, 0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, cmd, len));
/* Optimize the empty command. */
- if (m4_arg_empty (argv, 1))
+ if (!*cmd)
{
m4_set_sysval (0);
return;
@@ -658,11 +671,12 @@ M4BUILTIN_HANDLER (esyscmd)
m4_sysval_flush (context, false);
errno = 0;
- pin = popen (M4ARG (1), "r");
+ pin = popen (cmd, "r");
if (pin == NULL)
{
m4_error (context, 0, errno, me,
- _("cannot open pipe to command `%s'"), M4ARG (1));
+ _("cannot open pipe to command %s"),
+ quotearg_style (locale_quoting_style, cmd));
m4_set_sysval (-1);
}
else
diff --git a/modules/m4.c b/modules/m4.c
index 44e8a0a..8ce419d 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -504,20 +504,27 @@ m4_sysval_flush (m4 *context, bool report)
M4BUILTIN_HANDLER (syscmd)
{
+ const m4_call_info *me = m4_arg_info (argv);
+ const char *cmd = M4ARG (1);
+ size_t len = M4ARGLEN (1);
+
if (m4_get_safer_opt (context))
{
m4_error (context, 0, 0, m4_arg_info (argv), _("disabled by --safer"));
return;
}
+ if (strlen (cmd) != len)
+ m4_warn (context, 0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, cmd, len));
/* Optimize the empty command. */
- if (m4_arg_empty (argv, 1))
+ if (!*cmd)
{
m4_set_sysval (0);
return;
}
m4_sysval_flush (context, false);
- m4_sysval = system (M4ARG (1));
+ m4_sysval = system (cmd);
/* FIXME - determine if libtool works for OS/2, in which case the
FUNC_SYSTEM_BROKEN section on the branch must be ported to work
around the bug in their EMX libc system(). */
@@ -672,13 +679,19 @@ include (m4 *context, int argc, m4_macro_args *argv, bool
silent)
{
FILE *fp;
char *name = NULL;
+ const m4_call_info *me = m4_arg_info (argv);
+ const char *arg = M4ARG (1);
+ size_t len = M4ARGLEN (1);
- fp = m4_path_search (context, M4ARG (1), &name);
+ if (strlen (arg) != len)
+ m4_warn (context, 0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, arg, len));
+ fp = m4_path_search (context, arg, &name);
if (fp == NULL)
{
if (!silent)
m4_error (context, 0, errno, m4_arg_info (argv), _("cannot open %s"),
- quotearg_style (locale_quoting_style, M4ARG (1)));
+ quotearg_style (locale_quoting_style, arg));
return;
}
@@ -725,6 +738,12 @@ m4_make_temp (m4 *context, m4_obstack *obs, const
m4_call_info *caller,
successful. */
assert (obstack_object_size (obs) == 0);
obstack_grow (obs, quotes->str1, quotes->len1);
+ if (strlen (pattern) < len)
+ {
+ m4_warn (context, 0, caller, _("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')
@@ -740,10 +759,10 @@ m4_make_temp (m4 *context, m4_obstack *obs, const
m4_call_info *caller,
/* This use of _() will need to change if xgettext ever changes
its undocumented behavior of parsing both string options. */
- m4_error (context, 0, errno, caller,
- _(dir ? "cannot create directory from template `%s'"
- : "cannot create file from template `%s'"),
- pattern);
+ m4_warn (context, errno, caller,
+ _(dir ? "cannot create directory from template %s"
+ : "cannot create file from template %s"),
+ quotearg_style (locale_quoting_style, pattern));
obstack_free (obs, obstack_finish (obs));
}
else
diff --git a/tests/builtins.at b/tests/builtins.at
index f819403..397f649 100644
--- a/tests/builtins.at
+++ b/tests/builtins.at
@@ -1,5 +1,5 @@
# 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.
#
@@ -713,8 +713,8 @@ dnl Check that on error, the expansion is void
AT_DATA([[in]],
[[mkdtemp(`no_such_dir/m4-fooXXXXXX')
]])
-AT_CHECK_M4([in], [1], [[
-]], [[m4:in:1: mkdtemp: cannot create directory from template
`no_such_dir/m4-fooXXXXXX': No such file or directory
+AT_CHECK_M4([in], [0], [[
+]], [[m4:in:1: Warning: mkdtemp: cannot create directory from template
`no_such_dir/m4-fooXXXXXX': No such file or directory
]])
dnl Check that umask has an effect. drws--S--T is okay.
@@ -742,8 +742,8 @@ dnl Check that on error, the expansion is void
AT_DATA([[in]],
[[mkstemp(`no_such_dir/m4-fooXXXXXX')
]])
-AT_CHECK_M4([in], [1], [[
-]], [[m4:in:1: mkstemp: cannot create file from template
`no_such_dir/m4-fooXXXXXX': No such file or directory
+AT_CHECK_M4([in], [0], [[
+]], [[m4:in:1: Warning: mkstemp: cannot create file from template
`no_such_dir/m4-fooXXXXXX': No such file or directory
]])
dnl Check that extra X are appended, but not trailing NUL
diff --git a/tests/null.err b/tests/null.err
index edad891..01f2a8e 100644
--- a/tests/null.err
+++ b/tests/null.err
@@ -7,16 +7,19 @@ changeresyntax:
m4:null.m4:39: Warning: changeresyntax: bad syntax-spec: `\0'
changesyntax:
m4:null.m4:48: Warning: changesyntax: undefined syntax code: `\0'
+debugfile:
+m4:null.m4:52: Warning: debugfile: argument `/no/such\0/file' truncated
+m4:null.m4:52: Warning: debugfile: cannot set debug file `/no/such': No such
file or directory
debuglen:
-m4:null.m4:53: Warning: debuglen: non-numeric argument `1\0001'
+m4:null.m4:55: Warning: debuglen: non-numeric argument `1\0001'
decr:
-m4:null.m4:57: Warning: decr: non-numeric argument `1\0001'
+m4:null.m4:59: Warning: decr: non-numeric argument `1\0001'
defn:
-m4:null.m4:62: Warning: defn: undefined macro `\0-\0'
+m4:null.m4:64: Warning: defn: undefined macro `\0-\0'
divert:
-m4:null.m4:69: Warning: divert: non-numeric argument `1\0001'
+m4:null.m4:71: Warning: divert: non-numeric argument `1\0001'
dumpdef:
-m4:null.m4:77: Warning: dumpdef: undefined macro `\0-\0'
+m4:null.m4:79: Warning: dumpdef: undefined macro `\0-\0'
: `empty'
-: `dash'
- -: ``$0': $1'
@@ -24,34 +27,53 @@ m4:null.m4:77: Warning: dumpdef: undefined macro `\0-\0'
--: `dashes'
body: `- -'
errprint: - - - -
+esyscmd:
+m4:null.m4:89: Warning: esyscmd: argument `echo +\0+' truncated
eval:
-m4:null.m4:90: Warning: eval: bad input: `1\0+1'
-m4:null.m4:92: Warning: eval: non-numeric argument `2\0002'
-m4:null.m4:94: Warning: eval: non-numeric argument `1\0001'
+m4:null.m4:94: Warning: eval: bad input: `1\0+1'
+m4:null.m4:96: Warning: eval: non-numeric argument `2\0002'
+m4:null.m4:98: Warning: eval: non-numeric argument `1\0001'
format:
-m4:null.m4:99: Warning: format: unrecognized specifier in `%\0%'
-m4:null.m4:99: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:103: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:103: Warning: format: unrecognized specifier in `%\0%'
+include:
+m4:null.m4:113: Warning: include: argument `/no/such\0/file' truncated
+m4:null.m4:113: include: cannot open `/no/such': No such file or directory
incr:
-m4:null.m4:110: Warning: incr: non-numeric argument `1\0001'
+m4:null.m4:116: Warning: incr: non-numeric argument `1\0001'
index:
-m4:null.m4:116: Warning: index: non-numeric argument `1\0001'
+m4:null.m4:122: Warning: index: non-numeric argument `1\0001'
indir:
-m4:null.m4:121: Warning: indir: undefined macro `\0-\0'
-m4:null.m4:123: Warning: \0\0%%: extra arguments ignored: 1 > 0
+m4:null.m4:127: Warning: indir: undefined macro `\0-\0'
+m4:null.m4:129: Warning: \0\0%%: extra arguments ignored: 1 > 0
+maketemp:
+m4:null.m4:144: Warning: maketemp: recommend using mkstemp instead
+m4:null.m4:144: Warning: maketemp: argument `/no/such\0/file' truncated
+m4:null.m4:144: Warning: maketemp: cannot create file from template
`/no/such': No such file or directory
+mkdtemp:
+m4:null.m4:147: Warning: mkdtemp: argument `/no/such\0/file' truncated
+m4:null.m4:147: Warning: mkdtemp: cannot create directory from template
`/no/such': No such file or directory
+mkstemp:
+m4:null.m4:150: Warning: mkstemp: argument `/no/such\0/file' truncated
+m4:null.m4:150: Warning: mkstemp: cannot create file from template `/no/such':
No such file or directory
patsubst:
-m4:null.m4:141: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:151: Warning: patsubst: bad syntax-spec: `\0'
+m4:null.m4:153: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:163: Warning: patsubst: bad syntax-spec: `\0'
regexp:
-m4:null.m4:163: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:173: Warning: regexp: bad syntax-spec: `\0'
+m4:null.m4:175: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:185: Warning: regexp: bad syntax-spec: `\0'
renamesyms:
-m4:null.m4:178: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:184: Warning: renamesyms: bad syntax-spec: `\0'
+m4:null.m4:190: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:196: Warning: renamesyms: bad syntax-spec: `\0'
+sinclude:
+m4:null.m4:201: Warning: sinclude: argument `/no/such\0/file' truncated
substr:
-m4:null.m4:192: Warning: substr: non-numeric argument `1\0001'
-m4:null.m4:194: Warning: substr: non-numeric argument `1\0001'
+m4:null.m4:206: Warning: substr: non-numeric argument `1\0001'
+m4:null.m4:208: Warning: substr: non-numeric argument `1\0001'
+syscmd:
+m4:null.m4:214: Warning: syscmd: argument `echo +\0+' truncated
traceon:
m4trace: -1- - -(`- -') -> `strange: - -'
m4trace: -1- body -> ` - '
undivert:
-m4:null.m4:218: Warning: undivert: invalid file name `1\0001'
+m4:null.m4:234: Warning: undivert: invalid file name `1\0001'
diff --git a/tests/null.m4 b/tests/null.m4
index 3d57806..6071144 100644
--- a/tests/null.m4
+++ b/tests/null.m4
@@ -47,7 +47,9 @@ dnl Warning from changesyntax:
errprint(`changesyntax:
')changesyntax( )dnl
dnl Ignored by changesyntax: TODO - support ignored category?
-dnl Warning from debugfile: not tested yet. No file name includes NUL, needs
to warn
+dnl Warning from debugfile:
+errprint(`debugfile:
+')debugfile(`/no/such /file')dnl
dnl Warning from debuglen:
errprint(`debuglen:
')debuglen(`1 1')dnl
@@ -82,9 +84,11 @@ dumpdef(`body')dnl
dnl Passed through errprint:
errprint(`errprint:' - -, `- -
')dnl
-dnl Passed to esyscmd: not tested yet. NUL truncates string, needs to warn
+dnl Passed to esyscmd:
+`esyscmd:'errprint(`esyscmd:
+') esyscmd(`echo + +')sysval dnl
dnl Generated from esyscmd:
-`esyscmd:' esyscmd(__program__` -DNUL '__file__) sysval
+esyscmd(__program__` -DNUL '__file__) sysval
dnl First argument of eval:
errprint(`eval:
')eval(`1 +1')dnl
@@ -104,7 +108,9 @@ dnl Macro name in ifdef, passed through ifdef:
ifdef( , `oops: - -', `no: - -')
dnl Compared in ifelse, passed through ifelse:
`ifelse:' ifelse(`-', `- -', `oops', `- -', - -, `yes: - -')
-dnl Warning from include: not tested yet. No file name includes NUL, needs to
warn
+dnl Warning from include:
+errprint(`include:
+')include(`/no/such /file')dnl
dnl Warning from incr:
errprint(`incr:
')incr(`1 1')dnl
@@ -133,9 +139,15 @@ dnl Defined macro name in m4symbols:
dnl Passed through m4wrap:
m4wrap(``m4wrap:' - -
')dnl
-dnl Warning from maketemp: not tested yet. No file name includes NUL, needs to
warn
-dnl Warning from mkdtemp: not tested yet. No file name includes NUL, needs to
warn
-dnl Warning from mkstemp: not tested yet. No file name includes NUL, needs to
warn
+dnl Warning from maketemp:
+errprint(`maketemp:
+')maketemp(`/no/such /file')dnl
+dnl Warning from mkdtemp:
+errprint(`mkdtemp:
+')mkdtemp(`/no/such /file')dnl
+dnl Warning from mkstemp:
+errprint(`mkstemp:
+')mkstemp(`/no/such /file')dnl
dnl Bad regex in patsubst:
errprint(`patsubst:
')patsubst(`a', `\ \')dnl
@@ -184,7 +196,9 @@ dnl Syntax argument of renamesyms:
renamesyms(`a', `b', ` ')dnl
dnl Passed through shift:
`shift:' shift(`hi', `- -', - -)
-dnl Warning from sinclude: not tested yet. No file name includes NUL, needs to
warn
+dnl Warning from sinclude:
+errprint(`sinclude:
+')sinclude(`/no/such /file')dnl
dnl First argument of substr:
`substr:' substr(`-- --', `1', `3')dnl
dnl Second argument of substr:
@@ -195,7 +209,9 @@ substr(`abc', `1', `1 1')dnl
dnl Fourth argument of substr:
substr(`abc', `1', `1', `1 1')
dnl Warning from syncoutput: not tested yet. No mode contains NUL, needs to
warn
-dnl Passed to syscmd: not tested yet. NUL truncates string, needs to warn
+dnl Passed to syscmd:
+`syscmd:'errprint(`syscmd:
+') syscmd(`echo + +')sysval
dnl Sysval takes no arguments, and never produces NUL.
dnl Passed to traceoff:
traceoff(`- -', ` ')dnl
diff --git a/tests/null.out b/tests/null.out
index cfb78c0..3859b23 100644
--- a/tests/null.out
+++ b/tests/null.out
@@ -10,7 +10,8 @@ changesyntax: - - - -: dash echo .... dash- nul
define: - -
defn: `$0': $1 - -
divert: - -
-esyscmd: [ ] 0
+esyscmd: +
+0 [ ] 0
format: - -
ifdef: yes: - - no: - -
ifelse: yes: - -
@@ -25,6 +26,8 @@ regexp: 2 ! 1 - - -
renamesyms: 0 0
shift: - -,- -
substr: - - a1 1c
+syscmd: +
+0
traceon: strange: - - -
translit: - - . . cd
undefine: ok
diff --git a/tests/others.at b/tests/others.at
index 3f12351..779fd3c 100644
--- a/tests/others.at
+++ b/tests/others.at
@@ -430,7 +430,7 @@ $SED "s|null.m4|$abs_srcdir/null.m4|" <
"$abs_srcdir/null.out" > expout
$SED "s|null.m4|$abs_srcdir/null.m4|" < "$abs_srcdir/null.err" > experr
dnl all but m4exit
-AT_CHECK_M4([-Dm4exit -I "$abs_srcdir" null.m4], [0], [expout], [experr])
+AT_CHECK_M4([-Dm4exit -I "$abs_srcdir" null.m4], [1], [expout], [experr])
dnl just m4exit
AT_CHECK_M4(["$abs_srcdir/null.m4"], [1],
--
1.6.1.2
From 3e12364a5a32e5947b0c31a2ee6dc5351b7af5e6 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Tue, 10 Feb 2009 14:24:11 -0700
Subject: [PATCH 3/3] 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 <address@hidden>
---
ChangeLog | 22 +++++++++++++++
m4/debug.c | 29 +++++++++++++-------
m4/m4module.h | 4 +-
m4/macro.c | 7 +++--
m4/utility.c | 15 ++++++----
modules/format.c | 61 ++++++++++++++++++++++++++++--------------
modules/gnu.c | 12 +++++---
modules/m4.c | 8 +++--
src/freeze.c | 33 ++++++++++++++++++++---
src/main.c | 26 ++++++++++-------
tests/freeze.at | 14 +++++++++-
tests/null.err | 78 ++++++++++++++++++++++++++++++-----------------------
tests/null.m4 | 21 ++++++++++----
tests/null.out | 2 +-
tests/options.at | 5 ++-
15 files changed, 230 insertions(+), 107 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 29fc9ef..278093f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
2009-02-11 Eric Blake <address@hidden>
+ 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.
diff --git a/m4/debug.c b/m4/debug.c
index f5cb4e2..1e1e9a3 100644
--- a/m4/debug.c
+++ b/m4/debug.c
@@ -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 84c203e..07f8c1a 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 *);
diff --git a/m4/macro.c b/m4/macro.c
index 7e6ef47..738c8ca 100644
--- a/m4/macro.c
+++ b/m4/macro.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.
@@ -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 6d19526..215fabd 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 af983cd..55333be 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 69d938f..f44f0ba 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 8ce419d..1ad1ce1 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 0394d4c..1a03842 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);
diff --git a/src/main.c b/src/main.c
index b4d8da8..c2e19bd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 693ae54..338f6f5 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
index 01f2a8e..38c610f 100644
--- a/tests/null.err
+++ b/tests/null.err
@@ -12,14 +12,16 @@ m4:null.m4:52: Warning: debugfile: argument
`/no/such\0/file' truncated
m4:null.m4:52: Warning: debugfile: cannot set debug file `/no/such': No such
file or directory
debuglen:
m4:null.m4:55: Warning: debuglen: non-numeric argument `1\0001'
+debugmode:
+m4:null.m4:58: Warning: debugmode: bad debug flags: `-\0-'
decr:
-m4:null.m4:59: Warning: decr: non-numeric argument `1\0001'
+m4:null.m4:61: Warning: decr: non-numeric argument `1\0001'
defn:
-m4:null.m4:64: Warning: defn: undefined macro `\0-\0'
+m4:null.m4:66: Warning: defn: undefined macro `\0-\0'
divert:
-m4:null.m4:71: Warning: divert: non-numeric argument `1\0001'
+m4:null.m4:73: Warning: divert: non-numeric argument `1\0001'
dumpdef:
-m4:null.m4:79: Warning: dumpdef: undefined macro `\0-\0'
+m4:null.m4:81: Warning: dumpdef: undefined macro `\0-\0'
: `empty'
-: `dash'
- -: ``$0': $1'
@@ -28,52 +30,60 @@ m4:null.m4:79: Warning: dumpdef: undefined macro `\0-\0'
body: `- -'
errprint: - - - -
esyscmd:
-m4:null.m4:89: Warning: esyscmd: argument `echo +\0+' truncated
+m4:null.m4:91: Warning: esyscmd: argument `echo +\0+' truncated
eval:
-m4:null.m4:94: Warning: eval: bad input: `1\0+1'
-m4:null.m4:96: Warning: eval: non-numeric argument `2\0002'
-m4:null.m4:98: Warning: eval: non-numeric argument `1\0001'
+m4:null.m4:96: Warning: eval: bad input: `1\0+1'
+m4:null.m4:98: Warning: eval: non-numeric argument `2\0002'
+m4:null.m4:100: Warning: eval: non-numeric argument `1\0001'
format:
-m4:null.m4:103: Warning: format: unrecognized specifier in `%\0%'
-m4:null.m4:103: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:105: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:105: Warning: format: unrecognized specifier in `%\0%'
+m4:null.m4:107: Warning: format: non-numeric argument `1\0001'
+m4:null.m4:107: Warning: format: argument `-\0-' truncated
include:
-m4:null.m4:113: Warning: include: argument `/no/such\0/file' truncated
-m4:null.m4:113: include: cannot open `/no/such': No such file or directory
+m4:null.m4:116: Warning: include: argument `/no/such\0/file' truncated
+m4:null.m4:116: include: cannot open `/no/such': No such file or directory
incr:
-m4:null.m4:116: Warning: incr: non-numeric argument `1\0001'
+m4:null.m4:119: Warning: incr: non-numeric argument `1\0001'
index:
-m4:null.m4:122: Warning: index: non-numeric argument `1\0001'
+m4:null.m4:125: Warning: index: non-numeric argument `1\0001'
indir:
-m4:null.m4:127: Warning: indir: undefined macro `\0-\0'
-m4:null.m4:129: Warning: \0\0%%: extra arguments ignored: 1 > 0
+m4:null.m4:130: Warning: indir: undefined macro `\0-\0'
+m4:null.m4:132: Warning: \0\0%%: extra arguments ignored: 1 > 0
maketemp:
-m4:null.m4:144: Warning: maketemp: recommend using mkstemp instead
-m4:null.m4:144: Warning: maketemp: argument `/no/such\0/file' truncated
-m4:null.m4:144: Warning: maketemp: cannot create file from template
`/no/such': No such file or directory
+m4:null.m4:147: Warning: maketemp: recommend using mkstemp instead
+m4:null.m4:147: Warning: maketemp: argument `/no/such\0/file' truncated
+m4:null.m4:147: Warning: maketemp: cannot create file from template
`/no/such': No such file or directory
mkdtemp:
-m4:null.m4:147: Warning: mkdtemp: argument `/no/such\0/file' truncated
-m4:null.m4:147: Warning: mkdtemp: cannot create directory from template
`/no/such': No such file or directory
+m4:null.m4:150: Warning: mkdtemp: argument `/no/such\0/file' truncated
+m4:null.m4:150: Warning: mkdtemp: cannot create directory from template
`/no/such': No such file or directory
mkstemp:
-m4:null.m4:150: Warning: mkstemp: argument `/no/such\0/file' truncated
-m4:null.m4:150: Warning: mkstemp: cannot create file from template `/no/such':
No such file or directory
+m4:null.m4:153: Warning: mkstemp: argument `/no/such\0/file' truncated
+m4:null.m4:153: Warning: mkstemp: cannot create file from template `/no/such':
No such file or directory
patsubst:
-m4:null.m4:153: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:163: Warning: patsubst: bad syntax-spec: `\0'
+m4:null.m4:156: Warning: patsubst: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:166: Warning: patsubst: bad syntax-spec: `\0'
+popdef:
+m4:null.m4:173: Warning: popdef: undefined macro `-\0-'
regexp:
-m4:null.m4:175: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:185: Warning: regexp: bad syntax-spec: `\0'
+m4:null.m4:180: Warning: regexp: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:190: Warning: regexp: bad syntax-spec: `\0'
renamesyms:
-m4:null.m4:190: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
-m4:null.m4:196: Warning: renamesyms: bad syntax-spec: `\0'
+m4:null.m4:195: Warning: renamesyms: bad regular expression `\\\0\\': Trailing
backslash
+m4:null.m4:201: Warning: renamesyms: bad syntax-spec: `\0'
sinclude:
-m4:null.m4:201: Warning: sinclude: argument `/no/such\0/file' truncated
+m4:null.m4:206: Warning: sinclude: argument `/no/such\0/file' truncated
substr:
-m4:null.m4:206: Warning: substr: non-numeric argument `1\0001'
-m4:null.m4:208: Warning: substr: non-numeric argument `1\0001'
+m4:null.m4:211: Warning: substr: non-numeric argument `1\0001'
+m4:null.m4:213: Warning: substr: non-numeric argument `1\0001'
+syncoutput:
+m4:null.m4:218: Warning: syncoutput: unknown directive `\0'
syscmd:
-m4:null.m4:214: Warning: syscmd: argument `echo +\0+' truncated
+m4:null.m4:221: Warning: syscmd: argument `echo +\0+' truncated
traceon:
m4trace: -1- - -(`- -') -> `strange: - -'
m4trace: -1- body -> ` - '
+undefine:
+m4:null.m4:240: Warning: undefine: undefined macro `-\0-'
undivert:
-m4:null.m4:234: Warning: undivert: invalid file name `1\0001'
+m4:null.m4:243: Warning: undivert: invalid file name `1\0001'
diff --git a/tests/null.m4 b/tests/null.m4
index 6071144..0e13cb4 100644
--- a/tests/null.m4
+++ b/tests/null.m4
@@ -53,7 +53,9 @@ errprint(`debugfile:
dnl Warning from debuglen:
errprint(`debuglen:
')debuglen(`1 1')dnl
-dnl Warning from debugmode: not tested yet. NUL not a valid mode, needs to warn
+dnl Warning from debugmode:
+errprint(`debugmode:
+')debugmode(`- -')dnl
dnl Warning from decr:
errprint(`decr:
')decr(`1 1')dnl
@@ -100,8 +102,9 @@ dnl First argument to format:
`format:' format(`%s %s', `-', `-')dnl
dnl Invalid specifier in format:
errprint(`format:
-') format(`% %')
-dnl Numeric and string arguments to format: not tested yet, needs to warn
+') format(`% %')dnl
+dnl Numeric and string arguments to format:
+ format(`%d%s', `1 1', `- -')
dnl Character argument to format: not tested yet, %c semantics needed
dnl Macro name in ifdef, passed through ifdef:
`ifdef:' ifdef(`- -', `yes: - -', `oops: - -')dnl
@@ -165,7 +168,9 @@ dnl Replacement via reference in patsubst:
patsubst(`-- --', `-\(.\)-', `\1-\1')
dnl Defined argument of popdef:
`popdef:' popdef(`- -')ifdef(`- -', `oops', `ok')
-dnl Undefined argument of popdef: not tested yet. Should it warn?
+dnl Undefined argument of popdef:
+errprint(`popdef:
+')popdef(`- -')dnl
dnl Macro name of pushdef:
`pushdef:' pushdef(`- -', `strange: $1')ifdef(`- -', `ok', `oops')`'dnl
dnl Definition of pushdef:
@@ -208,7 +213,9 @@ dnl Third argument of substr:
substr(`abc', `1', `1 1')dnl
dnl Fourth argument of substr:
substr(`abc', `1', `1', `1 1')
-dnl Warning from syncoutput: not tested yet. No mode contains NUL, needs to
warn
+dnl Warning from syncoutput:
+errprint(`syncoutput:
+')syncoutput(` ')dnl
dnl Passed to syscmd:
`syscmd:'errprint(`syscmd:
') syscmd(`echo + +')sysval
@@ -228,7 +235,9 @@ dnl Character ranges of translit:
translit(`abcd', ` -b')
dnl Defined argument of undefine:
`undefine:' undefine(`- -')ifdef(`- -', `oops', `ok')
-dnl Undefined argument of undefine: not tested yet. Should it warn?
+dnl Undefined argument of undefine:
+errprint(`undefine:
+')undefine(`- -')dnl
dnl Warning from undivert:
errprint(`undivert:
')undivert(`1 1')dnl
diff --git a/tests/null.out b/tests/null.out
index 3859b23..993d9fe 100644
--- a/tests/null.out
+++ b/tests/null.out
@@ -12,7 +12,7 @@ defn: `$0': $1 - -
divert: - -
esyscmd: +
0 [ ] 0
-format: - -
+format: - - 1-
ifdef: yes: - - no: - -
ifelse: yes: - -
index: 2 -1 -1 8
diff --git a/tests/options.at b/tests/options.at
index 48e5b03..ad71f20 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
--
1.6.1.2
From 1b5e6019b86abfc086af32b79087b8e862ed7a81 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Tue, 5 Feb 2008 11:41:05 -0700
Subject: [PATCH] Stage 28: Allow embedded NUL in warning messages.
* src/m4.h (debug_decode): Add argument.
* src/m4.c (main): Adjust caller.
* src/format.c (arg_int, arg_long, arg_double): Likewise.
(arg_string): New function.
(ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE): Support embedded NUL.
* src/freeze.c (reload_frozen_state): Likewise.
* src/debug.c (debug_decode): Likewise.
* src/builtin.c (numeric_arg): Add argument.
(m4_syscmd, m4_esyscmd, m4_eval, m4_incr, m4_decr, m4_divert)
(m4_undivert, include, mkstemp_helper, m4_m4exit, m4_debugmode)
(m4_debugfile, m4_index, m4_substr): Detect embedded NUL.
(m4_defn, m4_maketemp, m4_placeholder): Improve warning message.
* src/path.c (m4_path_search): Likewise.
* doc/m4.texinfo (Syntax, Mkstemp, Using frozen files): Adjust
tests.
* examples/null.m4: Likewise.
* examples/null.out: Likewise.
* examples/null.err: Likewise.
Signed-off-by: Eric Blake <address@hidden>
(cherry picked from commit fd9f6463352aee342c4061b5df9d0f4bf56742c7)
---
ChangeLog | 28 ++++++++++++
doc/m4.texinfo | 20 ++++++++-
examples/null.err | 60 +++++++++++++++++++++++----
examples/null.m4 | 87 ++++++++++++++++++++++++++++----------
examples/null.out | 9 +++-
src/builtin.c | 121 ++++++++++++++++++++++++++++++++++++-----------------
src/debug.c | 30 ++++++++-----
src/format.c | 55 ++++++++++++++++--------
src/freeze.c | 13 ++++--
src/m4.c | 14 ++++---
src/m4.h | 2 +-
src/path.c | 10 +++-
12 files changed, 333 insertions(+), 116 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2aa09b4..39d40df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,33 @@
2009-02-11 Eric Blake <address@hidden>
+ Stage 28: Allow embedded NUL in warning messages.
+ Issue graceful error messages for a variety of places where
+ embedded NUL is otherwise unhandled. For example, numeric parsing
+ rejects embedded NUL, while file-related commands warn about
+ truncation at NUL, and frozen files detect unexpected NUL.
+ Memory impact: none.
+ Speed impact: none noticed.
+ * src/m4.h (debug_decode): Add argument.
+ * src/m4.c (main): Adjust caller.
+ * src/format.c (arg_int, arg_long, arg_double): Likewise.
+ (arg_string): New function.
+ (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE): Support embedded NUL.
+ * src/freeze.c (reload_frozen_state): Likewise.
+ * src/debug.c (debug_decode): Likewise.
+ * src/builtin.c (numeric_arg): Add argument.
+ (m4_syscmd, m4_esyscmd, m4_eval, m4_incr, m4_decr, m4_divert)
+ (m4_undivert, include, mkstemp_helper, m4_m4exit, m4_debugmode)
+ (m4_debugfile, m4_index, m4_substr): Detect embedded NUL.
+ (m4_defn, m4_maketemp, m4_placeholder): Improve warning message.
+ * src/path.c (m4_path_search): Likewise.
+ * doc/m4.texinfo (Syntax, Mkstemp, Using frozen files): Adjust
+ tests.
+ * examples/null.m4: Likewise.
+ * examples/null.out: Likewise.
+ * examples/null.err: Likewise.
+
+2009-02-11 Eric Blake <address@hidden>
+
Warn when popping traced but undefined macro.
* src/symtab.c (lookup_symbol): Recognize traced placeholder when
delete is requested. Bug introduced 2008-07-18.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index b337e5e..fd48e80 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -1081,14 +1081,16 @@ Syntax
@comment xout: null.out
@comment xerr: null.err
address@hidden status: 1
@example
define(`m4exit')include(`null.m4')dnl
@end example
address@hidden status: 2
address@hidden status: 1
@example
include(`null.m4')
@result{}# This file tests m4 behavior on NUL bytes.
address@hidden:examples/null.m4:5: Warning: m4exit: non-numeric argument
`2\0002'
@end example
@end ignore
@@ -7485,10 +7487,12 @@ Mkstemp
syscmd(`rm -f foo-??????')sysval
@result{}0
define(`file1', maketemp(`foo-XXXXXX'))dnl
address@hidden:stdin:3: Warning: maketemp: recommend using mkstemp instead
ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ',
`no file', `created')
@result{}created
define(`file2', maketemp(`foo-XX'))dnl
address@hidden:stdin:6: Warning: maketemp: recommend using mkstemp instead
define(`file3', mkstemp(`foo-XXXXXX'))dnl
ifelse(len(defn(`file1')), len(defn(`file2')),
`same length', `different')
@@ -7905,6 +7909,20 @@ Using frozen files
])dnl
@error{}divnum #-- 3 0
@end example
+
address@hidden Do we reject unexpected NUL bytes?
+
address@hidden
+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
address@hidden:in.m4f:4: ill-formed frozen file, invalid builtin `len\0'
encountered
address@hidden
address@hidden example
@end ignore
When an @code{m4} run is to be frozen, the automatic undiversion
diff --git a/examples/null.err b/examples/null.err
index 977b3b7..8446d78 100644
--- a/examples/null.err
+++ b/examples/null.err
@@ -5,10 +5,19 @@ echo: address@hidden/
m4trace: -1- dumpdef( echo/) -> /
changeword:
m4:examples/null.m4:43: Warning: changeword: bad regular expression `\\\0\\':
Trailing backslash
+debugfile:
+m4:examples/null.m4:49: Warning: debugfile: argument `/no/such\0/file'
truncated
+m4:examples/null.m4:49: Warning: debugfile: cannot set debug file `/no/such':
No such file or directory
+debugmode:
+m4:examples/null.m4:52: Warning: debugmode: bad debug flags: `-\0-'
+decr:
+m4:examples/null.m4:55: Warning: decr: non-numeric argument `1\0001'
defn:
-m4:examples/null.m4:54: Warning: defn: undefined macro `\0-\0'
+m4:examples/null.m4:60: Warning: defn: undefined macro `\0-\0'
+divert:
+m4:examples/null.m4:67: Warning: divert: non-numeric argument `1\0001'
dumpdef:
-m4:examples/null.m4:67: Warning: dumpdef: undefined macro `\0-\0'
+m4:examples/null.m4:75: Warning: dumpdef: undefined macro `\0-\0'
: `empty'
-: `dash'
- -: ``$0': $1'
@@ -16,16 +25,51 @@ m4:examples/null.m4:67: Warning: dumpdef: undefined macro
`\0-\0'
--: `dashes'
body: `- -'
errprint: - - - -
+esyscmd:
+m4:examples/null.m4:85: Warning: esyscmd: argument `echo +\0+' truncated
+eval:
+m4:examples/null.m4:90: Warning: eval: bad input: `1\0+1'
+m4:examples/null.m4:92: Warning: eval: non-numeric argument `2\0002'
+m4:examples/null.m4:94: Warning: eval: non-numeric argument `1\0001'
format:
-m4:examples/null.m4:84: Warning: format: unrecognized specifier in `%\0%'
-m4:examples/null.m4:84: Warning: format: unrecognized specifier in `%\0%'
+m4:examples/null.m4:99: Warning: format: unrecognized specifier in `%\0%'
+m4:examples/null.m4:99: Warning: format: unrecognized specifier in `%\0%'
+m4:examples/null.m4:101: Warning: format: non-numeric argument `1\0001'
+m4:examples/null.m4:101: Warning: format: argument `-\0-' truncated
+include:
+m4:examples/null.m4:110: Warning: include: argument `/no/such\0/file' truncated
+m4:examples/null.m4:110: include: cannot open `/no/such': No such file or
directory
+incr:
+m4:examples/null.m4:113: Warning: incr: non-numeric argument `1\0001'
+index:
+m4:examples/null.m4:119: Warning: index: non-numeric argument `1\0001'
indir:
-m4:examples/null.m4:101: Warning: indir: undefined macro `\0-\0'
-m4:examples/null.m4:103: Warning: \0\0%%: extra arguments ignored: 1 > 0
+m4:examples/null.m4:124: Warning: indir: undefined macro `\0-\0'
+m4:examples/null.m4:126: Warning: \0\0%%: extra arguments ignored: 1 > 0
+maketemp:
+m4:examples/null.m4:137: Warning: maketemp: recommend using mkstemp instead
+m4:examples/null.m4:137: Warning: maketemp: argument `/no/such\0/file'
truncated
+m4:examples/null.m4:137: Warning: maketemp: cannot create file from template
`/no/such': No such file or directory
+mkstemp:
+m4:examples/null.m4:140: Warning: mkstemp: argument `/no/such\0/file' truncated
+m4:examples/null.m4:140: Warning: mkstemp: cannot create file from template
`/no/such': No such file or directory
patsubst:
-m4:examples/null.m4:116: Warning: patsubst: bad regular expression `\\\0\\':
Trailing backslash
+m4:examples/null.m4:143: Warning: patsubst: bad regular expression `\\\0\\':
Trailing backslash
+popdef:
+m4:examples/null.m4:158: Warning: popdef: undefined macro `-\0-'
regexp:
-m4:examples/null.m4:136: Warning: regexp: bad regular expression `\\\0\\':
Trailing backslash
+m4:examples/null.m4:165: Warning: regexp: bad regular expression `\\\0\\':
Trailing backslash
+sinclude:
+m4:examples/null.m4:180: Warning: sinclude: argument `/no/such\0/file'
truncated
+substr:
+m4:examples/null.m4:185: Warning: substr: non-numeric argument `1\0001'
+m4:examples/null.m4:187: Warning: substr: non-numeric argument `1\0001'
+syscmd:
+m4:examples/null.m4:192: Warning: syscmd: argument `echo +\0+' truncated
traceon:
m4trace: -1- - -(`- -') -> `strange: - -'
m4trace: -1- body -> ` - '
+undefine:
+m4:examples/null.m4:208: Warning: undefine: undefined macro `-\0-'
+undivert:
+m4:examples/null.m4:214: Warning: undivert: invalid file name `1\0001'
diff --git a/examples/null.m4 b/examples/null.m4
index e60aec5..3f901f4 100644
--- a/examples/null.m4
+++ b/examples/null.m4
@@ -1,7 +1,7 @@
dnl Use `m4 -DNUL to print a NUL byte surrounded in [], then exit
ifdef(`NUL', `[ ]m4exit`'')dnl
# This file tests m4 behavior on NUL bytes.
-dnl Use `m4 -Dm4exit' to test rest of file. NUL not a number, needs to warn
+dnl Use `m4 -Dm4exit' to test rest of file.
m4exit(`2 2')dnl
dnl Raw pass-through:
raw: - -
@@ -44,9 +44,15 @@ errprint(`changeword:
ifdef(`c', `errprint(__program__:__file__:decr(__line__): Warning: dnl
`changeword: bad regular expression `\\\0\\': Trailing backslash
')')dnl
-dnl Warning from debugfile: not tested yet. No file name includes NUL, needs
to warn
-dnl Warning from debugmode: not tested yet. NUL not a valid mode, needs to warn
-dnl Warning from decr: not tested yet. NUL not a number, needs to warn
+dnl Warning from debugfile:
+errprint(`debugfile:
+')debugfile(`/no/such /file')dnl
+dnl Warning from debugmode:
+errprint(`debugmode:
+')debugmode(`- -')dnl
+dnl Warning from decr:
+errprint(`decr:
+')decr(`1 1')dnl
dnl Definition of define:
`define:' define(`body', `- -')body
dnl Undefined argument of defn:
@@ -56,7 +62,9 @@ dnl Defined macro name in defn:
`defn:' defn(`- -')dnl
dnl Macro contents in defn:
defn(`body')
-dnl Argument to divert: not tested yet. NUL not a number, needs to warn
+dnl Argument to divert:
+errprint(`divert:
+')divert(`1 1')dnl
dnl Passed through diversion by divert:
divert(`1')`divert:' - -
divert`'undivert(`1')dnl
@@ -72,28 +80,43 @@ dumpdef(`body')dnl
dnl Passed through errprint:
errprint(`errprint:' - -, `- -
')dnl
-dnl Passed to esyscmd: not tested yet. NUL truncates string, needs to warn
+dnl Passed to esyscmd:
+`esyscmd:'errprint(`esyscmd:
+') esyscmd(`echo + +')sysval dnl
dnl Generated from esyscmd:
-`esyscmd:' esyscmd(__program__` -DNUL '__file__) sysval
-dnl First argument of eval: not tested yet. NUL not a number, needs to warn
-dnl Other arguments of eval: not tested yet, needs to warn
+esyscmd(__program__` -DNUL '__file__) sysval
+dnl First argument of eval:
+errprint(`eval:
+')eval(`1 +1')dnl
+dnl Second argument of eval:
+eval(`1', `2 2')dnl
+dnl Third argument of eval:
+eval(`1', `10', `1 1')dnl
dnl First argument to format:
`format:' format(`%s %s', `-', `-')dnl
dnl Invalid specifier in format:
errprint(`format:
-') format(`% %')
-dnl Numeric and string arguments to format: not tested yet, needs to warn
+') format(`% %')dnl
+dnl Numeric and string arguments to format:
+ format(`%d%s', `1 1', `- -')
dnl Character argument to format: not tested yet, %c semantics needed
dnl Macro name in ifdef, passed through ifdef:
`ifdef:' ifdef(`- -', `yes: - -', `oops: - -')dnl
ifdef( , `oops: - -', `no: - -')
dnl Compared in ifelse, passed through ifelse:
`ifelse:' ifelse(`-', `- -', `oops', `- -', - -, `yes: - -')
-dnl Warning from include: not tested yet. No file name includes NUL, needs to
warn
-dnl Warning from incr: not tested yet. NUL not a number, needs to warn
+dnl Warning from include:
+errprint(`include:
+')include(`/no/such /file')dnl
+dnl Warning from incr:
+errprint(`incr:
+')incr(`1 1')dnl
dnl Passed through index:
`index:' index(`a b', `b') index(`-', ` ') index(` ', `-')dnl
index(` -', ` -')
+dnl Third argument of index:
+errprint(`index:
+')index(`aba', `a', `1 1')dnl
dnl Defined first argument of indir:
`indir:' indir(`- -', 1 1)dnl
dnl Undefined first argument of indir:
@@ -109,8 +132,12 @@ dnl Test m4exit separately from m4wrap; see above.
dnl Passed through m4wrap:
m4wrap(``m4wrap:' - -
')dnl
-dnl Warning from maketemp: not tested yet. No file name includes NUL, needs to
warn
-dnl Warning from mkstemp: not tested yet. No file name includes NUL, needs to
warn
+dnl Warning from maketemp:
+errprint(`maketemp:
+')maketemp(`/no/such /file')dnl
+dnl Warning from mkstemp:
+errprint(`mkstemp:
+')mkstemp(`/no/such /file')dnl
dnl Bad regex in patsubst:
errprint(`patsubst:
')patsubst(`a', `\ \')dnl
@@ -126,7 +153,9 @@ dnl Replacement via reference in patsubst:
patsubst(`-- --', `-\(.\)-', `\1-\1')
dnl Defined argument of popdef:
`popdef:' popdef(`- -')ifdef(`- -', `oops', `ok')
-dnl Undefined argument of popdef: not tested yet. Should it warn?
+dnl Undefined argument of popdef:
+errprint(`popdef:
+')popdef(`- -')dnl
dnl Macro name of pushdef:
`pushdef:' pushdef(`- -', `strange: $1')ifdef(`- -', `ok', `oops')`'dnl
dnl Definition of pushdef:
@@ -146,11 +175,21 @@ dnl Replacement via reference in regexp:
regexp(`-- --', `-\(.\)-', `\1-\1')
dnl Passed through shift:
`shift:' shift(`hi', `- -', - -)
-dnl Warning from sinclude: not tested yet. No file name includes NUL, needs to
warn
+dnl Warning from sinclude:
+errprint(`sinclude:
+')sinclude(`/no/such /file')dnl
dnl First argument of substr:
-`substr:' substr(`-- --', `1', `3')
-dnl Other arguments of substr: not tested yet. NUL not a number, needs to warn.
-dnl Passed to syscmd: not tested yet. NUL truncates string, needs to warn
+`substr:' substr(`-- --', `1', `3')dnl
+dnl Second argument of substr:
+errprint(`substr:
+')substr(`abc', `1 1')dnl
+dnl Third argument of substr:
+substr(`abc', `1', `1 1')dnl
+dnl Fourth argument of substr:
+ substr(`abc', `1', `1', `1 1')
+dnl Passed to syscmd:
+`syscmd:'errprint(`syscmd:
+') syscmd(`echo + +')sysval
dnl Sysval takes no arguments, and never produces NUL.
dnl Passed to traceoff:
traceoff(`- -', ` ')dnl
@@ -167,5 +206,9 @@ dnl Character ranges of translit:
translit(`abcd', ` -b')
dnl Defined argument of undefine:
`undefine:' undefine(`- -')ifdef(`- -', `oops', `ok')
-dnl Undefined argument of undefine: not tested yet. Should it warn?
-dnl Warning from undivert: not tested yet. No file name or number includes
NUL, needs to warn
+dnl Undefined argument of undefine:
+errprint(`undefine:
+')undefine(`- -')dnl
+dnl Warning from undivert:
+errprint(`undivert:
+')undivert(`1 1')dnl
diff --git a/examples/null.out b/examples/null.out
index c2c1cb9..812df0c 100644
--- a/examples/null.out
+++ b/examples/null.out
@@ -10,8 +10,9 @@ changeword: - - - -: dash
define: - -
defn: `$0': $1 - -
divert: - -
-esyscmd: [ ] 0
-format: - -
+esyscmd: +
+0 [ ] 0
+format: - - 1-
ifdef: yes: - - no: - -
ifelse: yes: - -
index: 2 -1 -1 8
@@ -22,7 +23,9 @@ popdef: ok
pushdef: ok -
regexp: 2 ! 1 - - -
shift: - -,- -
-substr: - -
+substr: - - a1 1c
+syscmd: +
+0
traceon: strange: - - -
translit: - - . . cd
undefine: ok
diff --git a/src/builtin.c b/src/builtin.c
index a398fdb..22d156d 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -564,18 +564,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"));
@@ -584,9 +584,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)))
@@ -1087,8 +1088,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;
@@ -1140,7 +1142,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;
@@ -1148,7 +1157,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
@@ -1165,10 +1174,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;
@@ -1177,10 +1191,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
@@ -1217,7 +1232,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)
@@ -1226,7 +1241,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)
{
@@ -1281,7 +1296,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);
@@ -1296,7 +1311,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);
@@ -1317,7 +1332,7 @@ m4_divert (struct obstack *obs, int argc, macro_arguments
*argv)
int i = 0;
bad_argc (me, argc, 0, 2);
- 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);
@@ -1357,11 +1372,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);
@@ -1473,16 +1493,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"),
- quotearg_style (locale_quoting_style, ARG (1)));
+ quotearg_style (locale_quoting_style, arg));
return;
}
@@ -1532,6 +1559,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')
@@ -1543,7 +1576,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
@@ -1562,6 +1596,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
@@ -1583,7 +1618,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;
@@ -1669,7 +1703,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)
{
@@ -1784,13 +1818,15 @@ 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);
bad_argc (me, argc, 0, 1);
if (argc == 1)
debug_level = 0;
- else if (debug_decode (str) < 0)
- m4_warn (0, me, _("bad debug flags: `%s'"), str);
+ else if (debug_decode (str, len) < 0)
+ m4_warn (0, me, _("bad debug flags: %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
}
/*-------------------------------------------------------------------------.
@@ -1807,9 +1843,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 debug file %s"),
- quotearg_style (locale_quoting_style, 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",
@@ -1855,7 +1899,8 @@ m4_index (struct obstack *obs, int argc, macro_arguments
*argv)
haystack = ARG (1);
haystack_len = ARG_LEN (1);
needle = ARG (2);
- if (!arg_empty (argv, 3) && !numeric_arg (arg_info (argv), ARG (3), &offset))
+ if (!arg_empty (argv, 3)
+ && !numeric_arg (arg_info (argv), ARG (3), ARG_LEN (3), &offset))
return;
if (offset < 0)
{
@@ -1907,7 +1952,7 @@ m4_substr (struct obstack *obs, int argc, macro_arguments
*argv)
}
length = ARG_LEN (1);
- if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), &start))
+ if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), ARG_LEN (2), &start))
return;
if (start < 0)
start += length;
@@ -1916,7 +1961,7 @@ m4_substr (struct obstack *obs, int argc, macro_arguments
*argv)
end = length;
else
{
- if (!numeric_arg (me, ARG (3), &end))
+ if (!numeric_arg (me, ARG (3), ARG_LEN (3), &end))
return;
if (end < 0)
end += length;
@@ -2406,8 +2451,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 b97fca3..8ed2d0d 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -1,7 +1,7 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1991, 1992, 1993, 1994, 2004, 2006, 2007, 2008 Free
- Software Foundation, Inc.
+ Copyright (C) 1991, 1992, 1993, 1994, 2004, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -43,25 +43,33 @@ 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 (). Return -1 |
-| if the parse failed, otherwise change the debug level. |
-`------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| 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. Return -1 if |
+| the parse failed, otherwise change the debug level. |
+`-------------------------------------------------------------------*/
int
-debug_decode (const char *opts)
+debug_decode (const char *opts, size_t len)
{
int level;
char mode = '\0';
- if (opts == NULL || *opts == '\0')
+ if (!opts)
+ opts = "";
+ if (len == SIZE_MAX)
+ len = strlen (opts);
+ if (!len)
level = DEBUG_TRACE_DEFAULT | debug_level;
else
{
if (*opts == '-' || *opts == '+')
- mode = *opts++;
- for (level = 0; *opts; opts++)
+ {
+ len--;
+ mode = *opts++;
+ }
+ for (level = 0; len--; opts++)
{
switch (*opts)
{
diff --git a/src/format.c b/src/format.c
index 8b2b11a..09cffa3 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 2648e39..1502532 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.
@@ -371,8 +371,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;
diff --git a/src/m4.c b/src/m4.c
index 91842e4..ef244e3 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -480,7 +480,7 @@ main (int argc, char *const *argv, char *const *envp)
break;
case 'E':
- debug_decode ("-d");
+ debug_decode ("-d", SIZE_MAX);
if (!fatal_warnings)
fatal_warnings = true;
else
@@ -530,8 +530,9 @@ main (int argc, char *const *argv, char *const *envp)
case 'd':
if (seen_file)
goto defer;
- if (debug_decode (optarg) < 0)
- error (0, 0, "bad debug flags: `%s'", optarg);
+ if (debug_decode (optarg, SIZE_MAX) < 0)
+ error (0, 0, "bad debug flags: %s",
+ quotearg_style (locale_quoting_style, optarg));
break;
case 'e':
@@ -603,7 +604,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
@@ -631,8 +632,9 @@ main (int argc, char *const *argv, char *const *envp)
break;
case 'd':
- if (debug_decode (arg) < 0)
- error (0, 0, "bad debug flags: `%s'", arg);
+ if (debug_decode (arg, SIZE_MAX) < 0)
+ error (0, 0, "bad debug flags: %s",
+ quotearg_style (locale_quoting_style, optarg));
break;
case 't':
diff --git a/src/m4.h b/src/m4.h
index 0611db4..b5521ca 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -205,7 +205,7 @@ extern FILE *debug;
#define DEBUG_TRACE_DEFAULT 0x407
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);
diff --git a/src/path.c b/src/path.c
index d630bad..0ed674c 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1,7 +1,7 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 2004, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 2004, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -176,7 +176,11 @@ 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)
*result = name;
else
--
1.6.1.2
- argv_ref patch 28: handle NUL in warning messages,
Eric Blake <=