From: Eric Blake Date: Mon, 24 Nov 2008 20:52:01 +0000 (-0700) Subject: Add safety check for m4_expand vs. diversions. X-Git-Tag: v2.63b~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb70cde184087a6abc547629aa3ecb771b7a4e87;p=thirdparty%2Fautoconf.git 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) : Document new safety check. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index c6c7109cf..043d79389 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-11-25 Eric Blake + + 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) : Document new + safety check. + 2008-11-24 Eric Blake Fix typo in AS_MESSAGE_LOG_FD patch. diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 957b8be57..7c7b9723d 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -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 diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index fd443ca99..55dcd4988 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -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