diff src/lstream.c @ 207:e45d5e7c476e r20-4b2

Import from CVS: tag r20-4b2
author cvs
date Mon, 13 Aug 2007 10:03:52 +0200
parents 3d6bfa290dbd
children 262b8bb4a523
line wrap: on
line diff
--- a/src/lstream.c	Mon Aug 13 10:02:48 2007 +0200
+++ b/src/lstream.c	Mon Aug 13 10:03:52 2007 +0200
@@ -714,13 +714,37 @@
 
   if (lstr->flags & LSTREAM_FL_IS_OPEN)
     {
-      /* don't return here on error, or file descriptor leak will result. */
       rc = Lstream_pseudo_close (lstr);
+      /*
+       * We used to return immediately if the closer method reported
+       * failure, leaving the stream open.  But this is no good, for
+       * the following reasons.
+       *
+       * 1. The finalizer method used in GC makes no provision for
+       *    failure, so we must not return without freeing buffer
+       *    memory.
+       *
+       * 2. The closer method may have already freed some memory
+       *    used for I/O in this stream.  E.g. encoding_closer frees
+       *    ENCODING_STREAM_DATA(stream)->runoff.  If a writer method
+       *    tries to use this buffer later, it will write into memory
+       *    that may have been allocated elsewhere.  Sometime later
+       *    you will see a sign that says "Welcome to Crash City."
+       *
+       * 3. The closer can report failure if a flush fails in the
+       *    other stream in a MULE encoding/decoding stream pair.
+       *    The other stream in the pair is closed, but returning
+       *    early leaves the current stream open.  If we try to
+       *    flush the current stream later, we will crash when the
+       *    flusher notices that the other end stream is closed.
+       *
+       * So, we no longer abort the close if the closer method
+       * reports some kind of failure.  We still report the failure
+       * to the caller.
+       */
       if (lstr->imp->closer)
-	{
-	  if ((lstr->imp->closer) (lstr) < 0)
-	    return -1;
-	}
+	if ((lstr->imp->closer) (lstr) < 0)
+	  rc = -1;
     }
 
   lstr->flags &= ~LSTREAM_FL_IS_OPEN;