[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Question about m4 include/sinclude

From: Roger Southwick
Subject: Re: Question about m4 include/sinclude
Date: Wed, 1 Oct 2008 00:04:25 -0700

Thanks Eric.  I think that will do the trick.  I'll e-mail the list again if it doesn't work out for me.

As an aside, if y'all are planning a m4 v2.0 release (like I think I've seen in the m4-discuss archive)
I'd like to suggest that the ability to ignore duplicate included files be built into the m4 program itself,
rather than pushdef/ifdef example.  Maybe enabled with a  --ignore-duplicate-include option.
I'd like the option to also manage the sinclude() lines also at the same time.
I'd implement in the C code by keeping track of the files ready by inode number and device mounted
on (rather than the path), like I thought about in my icky work-around.

Thanks again....


On Tue, Sep 30, 2008 at 6:19 PM, Eric Blake <address@hidden> wrote:
Hash: SHA1

According to address@hidden on 9/30/2008 4:49 PM:
> Without using ifdef or something similar, is there a way to prevent m4 from
> entering an infinite recursion with a file like:
> % cat foo
>    include(`foo')

No.  But WITH ifdef, there is a way, and in fact, autoconf uses it to
prohibit including a file more than once (not because of the fear of
infinite recursion, but because of the surprising number of .m4 include
files out there that define a macro with the first argument underquoted -
re-including the file would define a new macro, named by the definition of
the original macro, rather than being a no-op).

> I realize I can probably do something like define a macro in the file,
> and then not include
> the file if the macro is defined... HOWEVER, in my particular
> application, I cannot control all
> of the m4 files...

The trick is not doing it in the file, but before the file.  In other
words, redefine include to do additional work.  In other words, the act of
calling include defines a witness macro, such that if the witness macro is
defined, you are recursively (or repeatedly) trying to re-include the file.

pushdef(`include', `ifelse(`$#', `0', ``$0'',
  `ifelse(`$1 has been seen;
          replace this no-op comment with m4exit if desired')',
  `define(`include($1)')builtin(`$0', $@)')')')
pushdef(`sinclude', defn(`include'))

The ifelse comment there can be turned into a warning (via errprint) or
error (via m4exit) if desired.  And this works independently of the file
contents (so you can protect yourself against malicious include files, as
appears to be your goal).

> And my m4 go off into an infinite loop.  I can control command line
> options, but
> when I tried --nesting-limit=1, that didn't seem to help.

- --nesting-limit only controls textual nesting (such as
"include(include(foo))"), not recursive invocation.  In the case of
recursive invocation, each macro is expanded at the outermost level of
textual nesting.

> About all I could think of is to have my Perl script I'm calling m4 from
> pre-process the
> files looking for include or sinclude lines, taking into account the
> M4PATH environment
> files, and making sure I don't repeat files (using something like stat()
> and the inode and
> device to make sure I handle symlinks).

I agree - that seems gross.  And as autoconf developers have already
noted, m4 is the best language for parsing m4 - it is almost impossible to
write robust perl scripts that still handle all cases of m4 input reliably.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]