]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Add safety check for m4_expand vs. diversions.
authorEric Blake <ebb9@byu.net>
Mon, 24 Nov 2008 20:52:01 +0000 (13:52 -0700)
committerEric Blake <ebb9@byu.net>
Tue, 25 Nov 2008 16:10:25 +0000 (09:10 -0700)
* lib/m4sugar/m4sugar.m4 (m4_expand): Make more robust against
diverted text.
* doc/autoconf.texi (Evaluation Macros) <m4_expand>: Document new
safety check.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
doc/autoconf.texi
lib/m4sugar/m4sugar.m4

index c6c7109cfea0534b9259996079b5a40c59fbe751..043d7938949936b0c701195b0977540c849af1b8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-11-25  Eric Blake  <ebb9@byu.net>
+
+       Add safety check for m4_expand vs. diversions.
+       * lib/m4sugar/m4sugar.m4 (m4_expand): Make more robust against
+       diverted text.
+       * doc/autoconf.texi (Evaluation Macros) <m4_expand>: Document new
+       safety check.
+
 2008-11-24  Eric Blake  <ebb9@byu.net>
 
        Fix typo in AS_MESSAGE_LOG_FD patch.
index 957b8be579aa4a49e9b24718faf2e923f2ddc845..7c7b9723ddff4d35edc86ae0c209677c7545cb9a 100644 (file)
@@ -10725,10 +10725,37 @@ dubious syntactic constructs, incorrectly ordered macro calls.
 M4sugar makes heavy use of diversions, because it is often the case that
 text that must appear early in the output is not discovered until late
 in the input.  Additionally, some of the topological sorting algorithms
-used in resolving macro dependencies use diversions.  Therefore, most
+used in resolving macro dependencies use diversions.  However, most
 macros should not need to change diversions directly, but rather rely on
 higher-level M4sugar macros to manage diversions transparently.
 
+In the rare case that it is necessary to write a macro that explicitly
+outputs text to a different diversion, it is important to be aware of an
+M4 limitation regarding diversions: text only goes to a diversion if it
+is not part of argument collection.  Therefore, any macro that changes
+the current diversion cannot be used as an unquoted argument to another
+macro, but must be expanded at the top level.  The macro
+@code{m4_expand} will diagnose any attempt to change diversions, since
+it is generally useful only as an argument to another macro.  The
+following example shows what happens when diversion manipulation is
+attempted within macro arguments:
+
+@example
+m4_do([normal text]
+m4_divert_push([KILL])unwanted[]m4_divert_pop([KILL])
+[m4_divert_push([KILL])discarded[]m4_divert_pop([KILL])])dnl
+@result{}normal text
+@result{}unwanted
+@end example
+
+@noindent
+Notice that the unquoted text @code{unwanted} is output, even though it
+was processed while the current diversion was @code{KILL}, because it
+was collected as part of the argument to @code{m4_do}.  However, the
+text @code{discarded} disappeared as desired, because the diversion
+changes were single-quoted, and were not expanded until the top-level
+rescan of the output of @code{m4_do}.
+
 To make diversion management easier, M4sugar uses the concept of named
 diversions.  Rather than using diversion numbers directly, it is nicer
 to associate a name with each diversion; the diversion number associated
@@ -11295,7 +11322,10 @@ whitespace is preserved, even after the expansion of macros contained in
 @var{arg}.  Additionally, @code{m4_expand} is able to expand text that
 would involve an unterminated comment, whereas expanding that same text
 as the argument to @code{m4_quote} runs into difficulty in finding the
-end of the argument.
+end of the argument.  Since manipulating diversions during argument
+collection is inherently unsafe, @code{m4_expand} issues an error if
+@var{arg} attempts to change the current diversion (@pxref{Diversion
+support}).
 
 @example
 m4_define([active], [ACT, IVE])dnl
index fd443ca9987201181e3c471b9d47d073cc2b7744..55dcd4988569140dca0246ec78ca59009268d26d 100644 (file)
@@ -832,8 +832,11 @@ m4_define([m4_echo], [$@])
 # this), and should not contain the unlikely delimiters -=<{( or
 # )}>=-.  It is possible to have unbalanced quoted `(' or `)', as well
 # as unbalanced unquoted `)'.  m4_expand can handle unterminated
-# comments or dnl on the final line, at the expense of speed, while
-# _m4_expand is faster but must be given a terminated expansion.
+# comments or dnl on the final line, at the expense of speed; it also
+# aids in detecting attempts to incorrectly change the current
+# diversion inside ARG.  Meanwhile, _m4_expand is faster but must be
+# given a terminated expansion, and has no safety checks for
+# mis-diverted text.
 #
 # Exploit that extra unquoted () will group unquoted commas and the
 # following whitespace.  m4_bpatsubst can't handle newlines inside $1,
@@ -848,8 +851,11 @@ m4_define([m4_echo], [$@])
 # this time with one more `(' in the second argument and in the
 # open-quote delimiter.  We must also ignore the slop from the
 # previous try.  The final macro is thus half line-noise, half art.
-m4_define([m4_expand], [m4_chomp(_$0([$1
-]))])
+m4_define([m4_expand],
+[m4_pushdef([m4_divert], _m4_defn([_m4_divert_unsafe]))]dnl
+[m4_pushdef([m4_divert_push], _m4_defn([_m4_divert_unsafe]))]dnl
+[m4_chomp(_$0([$1
+]))_m4_popdef([m4_divert], [m4_divert_push])])
 
 m4_define([_m4_expand], [$0_([$1], [(], -=<{($1)}>=-, [}>=-])])
 
@@ -1380,6 +1386,15 @@ m4_define([m4_divert_once],
 [m4_expand_once([m4_divert_text([$1], [$2])])])
 
 
+# _m4_divert_unsafe(DIVERSION-NAME)
+# ---------------------------------
+# Issue a warning that the attempt to change the current diversion to
+# DIVERSION-NAME is unsafe, because this macro is being expanded
+# during argument collection of m4_expand.
+m4_define([_m4_divert_unsafe],
+[m4_fatal([$0: cannot change diversion to `$1' inside m4_expand])])
+
+
 # m4_undivert(DIVERSION-NAME...)
 # ------------------------------
 # Undivert DIVERSION-NAME.  Unlike the M4 version, this requires at