Re: add some fd tests to head

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
Eric Blake <ebb9 <at> byu.net> writes:

> 
> 2006-11-07  Eric Blake  <ebb9 <at> byu.net>
> 
> 	* tests/builtins.at (m4exit): New test; failed on cygwin before
> 	this patch.
> 	* m4/output.c (cleanup_tmpfile): Close files before removing
> 	directory.
> 	(make_room_for): Ensure that m4_error sees consistent state.

And this followup.

2006-11-07  Eric Blake  <[email protected]>

	* m4/output.c (cleanup_tmpfile, m4_insert_diversion_helper): Check
	for failure.

Index: m4/output.c
===================================================================
RCS file: /sources/m4/m4/m4/output.c,v
retrieving revision 1.36
diff -u -r1.36 output.c
--- m4/output.c	8 Nov 2006 04:26:53 -0000	1.36
+++ m4/output.c	8 Nov 2006 05:02:55 -0000
@@ -174,6 +174,7 @@
   m4_diversion *diversion;
   gl_list_iterator_t iter;
   const void *elt;
+  bool fail = false;
 
   if (diversion_table)
     {
@@ -182,14 +183,21 @@
       while (gl_list_iterator_next (&iter, &elt, NULL))
 	{
 	  diversion = (m4_diversion *) elt;
-	  if (!diversion->size && diversion->u.file)
-	    close_stream_temp (diversion->u.file);
+	  if (!diversion->size && diversion->u.file &&
+	      close_stream_temp (diversion->u.file) != 0)
+	    {
+	      error (0, errno,
+		     _("cannot clean temporary file for diversion"));
+	      fail = true;
+	    }
 	}
       gl_list_iterator_free (&iter);
     }
 
   /* Clean up the temporary directory.  */
   if (cleanup_temp_dir (output_temp_dir) != 0)
+    fail = true;
+  if (fail)
     _exit (exit_failure);
 }
 
@@ -664,8 +672,9 @@
       diversion->size = 0;
       diversion->used = 0;
     }
-  else if (diversion->u.file)
-    close_stream_temp (diversion->u.file);
+  else if (diversion->u.file && close_stream_temp (diversion->u.file) != 0)
+    m4_error (context, 0, errno,
+	      _("cannot clean temporary file for diversion"));
   gl_list_remove_node (diversion_table, node);
   diversion->u.next = free_list;
   free_list = diversion;


Today's patches ported to the branch as follows.

2006-11-07  Eric Blake  <[email protected]>

	* src/m4.h (output_exit): New prototype.
	* src/m4.c (main): Use it.
	* src/output.c (cleanup_tmpfile): Close files before removing
	directory.
	(insert_diversion): Check for failure.
	(output_exit): Avoid memory leak.
	* doc/m4.texinfo (Diversions): Test this bug.

Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.98
diff -u -r1.1.1.1.2.98 m4.texinfo
--- doc/m4.texinfo	7 Nov 2006 19:14:03 -0000	1.1.1.1.2.98
+++ doc/m4.texinfo	8 Nov 2006 05:01:34 -0000
@@ -3621,6 +3621,38 @@
 divert(`-1')undivert
 @end example
 
+@comment Another test of spilled diversions.
+
+@example
+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'))
+define(`f', defn(`f')defn(`f'))
+divert`'dnl
+len(f)
+@result{}1048576
+divert(`1')
+f
+m4exit
+@end example
+
 @comment We also need to test allocation overflow.  On 32-bit
 @comment platforms, this should fail outright.  But on 64-bit platforms
 @comment with enough memory, the allocation might succeed (hopefully
Index: src/m4.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/m4.c,v
retrieving revision 1.1.1.1.2.37
diff -u -r1.1.1.1.2.37 m4.c
--- src/m4.c	1 Nov 2006 22:29:08 -0000	1.1.1.1.2.37
+++ src/m4.c	8 Nov 2006 05:01:34 -0000
@@ -576,5 +576,6 @@
       make_diversion (0);
       undivert_all ();
     }
+  output_exit ();
   exit (retcode);
 }
Index: src/m4.h
===================================================================
RCS file: /sources/m4/m4/src/m4.h,v
retrieving revision 1.1.1.1.2.33
diff -u -r1.1.1.1.2.33 m4.h
--- src/m4.h	1 Nov 2006 22:29:08 -0000	1.1.1.1.2.33
+++ src/m4.h	8 Nov 2006 05:01:34 -0000
@@ -311,6 +311,7 @@
 extern int output_current_line;
 
 void output_init (void);
+void output_exit (void);
 void shipout_text (struct obstack *, const char *, int);
 void make_diversion (int);
 void insert_diversion (int);
Index: src/output.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/output.c,v
retrieving revision 1.1.1.1.2.14
diff -u -r1.1.1.1.2.14 output.c
--- src/output.c	1 Nov 2006 22:29:08 -0000	1.1.1.1.2.14
+++ src/output.c	8 Nov 2006 05:01:34 -0000
@@ -106,13 +106,39 @@
   output_unused = 0;
 }
 
+void
+output_exit (void)
+{
+  free (diversion_table);
+  diversion_table = NULL;
+}
+
 /* Clean up any temporary directory.  Designed for use as an atexit
    handler, where it is not safe to call exit() recursively; so this
    calls _exit if a problem is encountered.  */
 static void
 cleanup_tmpfile (void)
 {
+  /* Close any open diversions.  */
+  int divnum;
+  struct diversion *diversion;
+  bool fail = false;
+
+  if (diversion_table)
+    for (divnum = 1; divnum < diversions; divnum++)
+      {
+	diversion = diversion_table + divnum;
+	if (diversion->file && close_stream_temp (diversion->file) != 0)
+	  {
+	    M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+	    fail = true;
+	  }
+      }
+
+  /* Clean up the temporary directory.  */
   if (cleanup_temp_dir (output_temp_dir) != 0)
+    fail = true;
+  if (fail)
     _exit (exit_failure);
 }
 
@@ -531,7 +557,8 @@
 
   if (diversion->file)
     {
-      close_stream_temp (diversion->file);
+      if (close_stream_temp (diversion->file) != 0)
+	M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
       diversion->file = NULL;
     }
   else if (diversion->buffer)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.