I'm still thinking about how best to patch this.  I know gnulib provides the 
stdio-safer module (and friends) that guarantee that stdio functions like fopen 
don't reuse fd's 0, 1, or 2 (and hence that stdin, stdout, and stderr remain 
closed if they started life closed).  I also know that gnulib provides the 
closeout module, which we should probably be using (and issue an error if any 
output was attempted to stdout when it was already closed).

As a demonstration of the sorts of bugs currently in m4:

$ echo dnl | m4 -tdnl -oout
$ cat out
m4trace: -1- dnl
$ rm out
$ echo dnl | m4 -tdnl -oout >&-
$ cat out
$

Oops.  When stdout is closed, out gets created with fd 1.  Then in debug.c's 
debug_set_file, we see if fileno(stdout) and fileno(debug) are the same file 
(they are, since they are both fd 1), and close debug in favor of stdout.  
Which means we lose all trace data, even though the above invocation is 
perfectly legal (there was nothing written to stdout, so it shouldn't matter 
whether stdout was closed).

$ echo hi | m4 >&-
$ echo $?
0
$

Oops.  We should have issued an error to stdout stating we had a write error, 
and exited with non-zero status.

$ m4 -tdnl 2>&- |tail
divert(-1)
define(f,`
')
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
define(`f',defn(`f')defn(`f'))
# f is now 2^20 bytes, large enough to overflow diversions into tmp file
divert(1)
f
divert
dnl()
undivert
bye
^D




stdin:27: m4: Warning: excess arguments to builtin `dnl' ignored
m4trace: -1- dnl



bye
$

Oops - the diversion spill opened fd 2, and messages to stderr got captured by 
the tmp file, and undiverted into stdout, rather than discarded because stderr 
was closed.

-- 
Eric Blake





_______________________________________________
Bug-m4 mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-m4

Reply via email to