m4-patches
[Top][All Lists]
Advanced

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

fix freezing of large diversions


From: Eric Blake
Subject: fix freezing of large diversions
Date: Mon, 28 May 2007 13:50:44 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10) Gecko/20070221 Thunderbird/1.5.0.10 Mnenhy/0.7.5.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I noticed that cygwin rewind() had a bug (it failed to clear the error
mark on a stream), but that using rewind is inherently unsafe to begin
with (since there is no indication when an error occurred during the flush
prior to clearing the error mark).  And in the process of getting rid of
the use of rewind, I managed to trigger some asserts on head when trying
to freeze a 1 megabyte diversion.  The same bug is present on the branch
(minus the asserts, so behavior was even less predictable), so I will be
checking a version of this in on both branches.

On platforms with large files, it is still not possible to freeze more
than 2 GiB in a single diversion.  I'm wondering how best to do this;
particularly on platforms where off_t is 64 bits but size_t is 32 bits.
But I would like to see it fixed, since even 2GiB is an arbitrary limit.

2007-05-28  Eric Blake  <address@hidden>

        Fix large diversion corner cases.
        * tests/freeze.at (large diversion): New test.
        * m4/output.c (m4_tmpfile, m4_tmpopen): Simplify use of errno.
        (make_room_for): Use NULL, not 0, for pointers.
        (m4_freeze_diversions): Allow freezing large diversions.
        (insert_diversion_helper): Avoid using rewind.

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

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGWzKT84KuGfSFAYARAlO5AJ0dhfRZLArlNQjv3Z0ZOpxyRZTgSQCeJWLG
GW4R6zXOdGKP1xWMdO/VtjY=
=DC9w
-----END PGP SIGNATURE-----
Index: m4/output.c
===================================================================
RCS file: /sources/m4/m4/m4/output.c,v
retrieving revision 1.42
diff -u -p -r1.42 output.c
--- m4/output.c 2 Apr 2007 12:06:23 -0000       1.42
+++ m4/output.c 28 May 2007 19:42:06 -0000
@@ -215,7 +215,6 @@ m4_tmpfile (m4 *context, int divnum)
 
   if (output_temp_dir == NULL)
     {
-      errno = 0;
       output_temp_dir = create_temp_dir ("m4-", NULL, true);
       if (output_temp_dir == NULL)
        m4_error (context, EXIT_FAILURE, errno,
@@ -224,7 +223,6 @@ m4_tmpfile (m4 *context, int divnum)
     }
   name = m4_tmpname (divnum);
   register_temp_file (output_temp_dir, name);
-  errno = 0;
   file = fopen_temp (name, O_BINARY ? "wb+" : "w+");
   if (file == NULL)
     {
@@ -246,7 +244,6 @@ m4_tmpopen (m4 *context, int divnum)
   const char *name = m4_tmpname (divnum);
   FILE *file;
 
-  errno = 0;
   file = fopen_temp (name, O_BINARY ? "ab+" : "a+");
   if (file == NULL)
     m4_error (context, EXIT_FAILURE, errno,
@@ -374,7 +371,7 @@ make_room_for (m4 *context, size_t lengt
       if (selected_diversion)
        {
          FILE *file = selected_diversion->u.file;
-         selected_diversion->u.file = 0;
+         selected_diversion->u.file = NULL;
          if (m4_tmpclose (file) != 0)
            m4_error (context, 0, errno,
                      _("cannot close temporary file for diversion"));
@@ -720,13 +717,10 @@ insert_diversion_helper (m4 *context, m4
        output_text (context, diversion->u.buffer, diversion->used);
       else
        {
-         if (!diversion->u.file && diversion->used)
+         assert (diversion->used);
+         if (!diversion->u.file)
            diversion->u.file = m4_tmpopen (context, diversion->divnum);
-         if (diversion->u.file)
-           {
-             rewind (diversion->u.file);
-             m4_insert_file (context, diversion->u.file);
-           }
+         m4_insert_file (context, diversion->u.file);
        }
 
       m4_set_output_line (context, -1);
@@ -816,7 +810,7 @@ m4_freeze_diversions (m4 *context, FILE 
   while (gl_oset_iterator_next (&iter, &elt))
     {
       m4_diversion *diversion = (m4_diversion *) elt;
-      if (diversion->size || diversion->u.file)
+      if (diversion->size || diversion->used)
        {
          if (diversion->size)
            {
@@ -827,18 +821,19 @@ m4_freeze_diversions (m4 *context, FILE 
          else
            {
              struct stat file_stat;
-             fflush (diversion->u.file);
+             assert (!diversion->u.file);
+             diversion->u.file = m4_tmpopen (context, diversion->divnum);
              if (fstat (fileno (diversion->u.file), &file_stat) < 0)
                m4_error (context, EXIT_FAILURE, errno,
                          _("cannot stat diversion"));
              /* FIXME - support 64-bit off_t with 32-bit long, and
-                fix frozen file format to support 64-bit
-                integers.  */
+                fix frozen file format to support 64-bit integers.
+                This implies fixing shipout_text to take off_t.  */
              if (file_stat.st_size < 0
                  || file_stat.st_size != (unsigned long int) file_stat.st_size)
                m4_error (context, EXIT_FAILURE, errno,
                          _("diversion too large"));
-             fprintf (file, "D%d,%lu", diversion->divnum,
+             fprintf (file, "D%d,%lu\n", diversion->divnum,
                       (unsigned long int) file_stat.st_size);
            }
 
Index: tests/freeze.at
===================================================================
RCS file: /sources/m4/m4/tests/freeze.at,v
retrieving revision 1.10
diff -u -p -r1.10 freeze.at
--- tests/freeze.at     25 Feb 2007 22:43:55 -0000      1.10
+++ tests/freeze.at     28 May 2007 19:42:06 -0000
@@ -19,6 +19,41 @@
 
 AT_BANNER([Freezing state.])
 
+## --------------- ##
+## large diversion ##
+## --------------- ##
+
+AT_SETUP([large diversion])
+AT_KEYWORDS([frozen])
+
+# Check that large diversions are handled across freeze boundaries.
+
+AT_DATA([[frozen.m4]], [M4_ONE_MEG_DEFN[divert(2)f
+divert(1)hi
+]])
+
+AT_DATA([[unfrozen.m4]],
+[[divert(3)bye
+]])
+
+# First generate the `expout' output by running over the sources before
+# freezing.
+AT_CHECK_M4([frozen.m4 unfrozen.m4], [0],
+           [stdout], [stderr])
+
+mv stdout expout
+mv stderr experr
+
+# Now freeze the first source file.
+AT_CHECK_M4([-F frozen.m4f frozen.m4], [0])
+
+# Now rerun the original sequence, but using the frozen file.
+AT_CHECK_M4([-R frozen.m4f unfrozen.m4], [0],
+           [expout], [experr])
+
+AT_CLEANUP
+
+
 ## ---------------- ##
 ## loading format 1 ##
 ## ---------------- ##

reply via email to

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