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
