Here are two patches that address the current bug, for comparison.

apr_dupfix.patch keeps the cleanup_kill -> dup2 -> register_cleanup
logic that protects us from dup2'ing into an apr_file_close()ed fd.

apr_duprevert.patch keeps the reorganization of the code, but drops
the cleanup_kill and register_cleanup in the dup2 case, in favor of 
trusting the current cleanups (and that they correpond to ->flags.)

I honestly like the second patch better, only if we agree to not support
apr_file_dup2()ing into any apr_file_t that's already been apr_file_close()d.
Supporting that behavior will be a PITA on Win32.

In *BOTH* patches we revert apr_file_dup() assumption that fd 0..2 are 
inherited, to reflect Jeff's concern with that change.

Please express a preference and I'll commit the favored patch and
test on OS/X prior to T&R of 0.9.2.

Bill
Index: file_io/unix/filedup.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/filedup.c,v
retrieving revision 1.60
diff -u -r1.60 filedup.c
--- file_io/unix/filedup.c      19 Mar 2003 10:17:26 -0000      1.60
+++ file_io/unix/filedup.c      21 Mar 2003 17:31:58 -0000
@@ -117,16 +117,23 @@
     /* make sure unget behavior is consistent */
     (*new_file)->ungetchar = old_file->ungetchar;
 
-    /* apr_file_dup() clears the inherit attribute for normal files,
-     * but sets the inherit attribute for std[out,in,err] fd's. 
-     * The user must call apr_file_inherit_[un]set() on the dupped 
-     * apr_file_t when desired.
-     */
-    if ((*new_file)->filedes <= 2) {
-        (*new_file)->flags = old_file->flags | APR_INHERIT;
+    if (which_dup == 1) {
+        /* apr_file_dup() retains all old_file flags with the exceptions
+         * of APR_INHERIT and APR_FILE_NOCLEANUP.
+         * The user must call apr_file_inherit_set() on the dupped 
+         * apr_file_t when desired.
+         */
+        (*new_file)->flags = old_file->flags
+                           & ~(APR_INHERIT | APR_FILE_NOCLEANUP);
     }
-    else {
-        (*new_file)->flags = old_file->flags & ~APR_INHERIT;
+    else /* which_dup == 2 */ {
+        /* apr_file_dup2() must respect the original settings for the
+         * new_file->flags inheritence.  If there is no cleanup, we
+         * are finished already
+         */
+        if ((*new_file)->flags & APR_FILE_NOCLEANUP) {
+            return APR_SUCCESS;
+        }
     }
 
     apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
Index: file_io/unix/filedup.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/filedup.c,v
retrieving revision 1.60
diff -u -r1.60 filedup.c
--- file_io/unix/filedup.c      19 Mar 2003 10:17:26 -0000      1.60
+++ file_io/unix/filedup.c      21 Mar 2003 22:31:05 -0000
@@ -117,23 +117,27 @@
     /* make sure unget behavior is consistent */
     (*new_file)->ungetchar = old_file->ungetchar;
 
-    /* apr_file_dup() clears the inherit attribute for normal files,
-     * but sets the inherit attribute for std[out,in,err] fd's. 
-     * The user must call apr_file_inherit_[un]set() on the dupped 
-     * apr_file_t when desired.
+    /* apr_file_dup2() retains the original cleanup, reflecting 
+     * the correct inherit and nocleanup flags.  However, 
+     * apr_file_dup2() cannot be called against an apr_file_t
+     * closed with apr_file_close, since the cleanup has been
+     * destroyed already.
      */
-    if ((*new_file)->filedes <= 2) {
-        (*new_file)->flags = old_file->flags | APR_INHERIT;
-    }
-    else {
-        (*new_file)->flags = old_file->flags & ~APR_INHERIT;
+    if (which_dup == 2) {
+        return APR_SUCCESS;
     }
 
+    /* apr_file_dup() retains all old_file flags with the exceptions
+     * of APR_INHERIT and APR_FILE_NOCLEANUP.
+     * The user must call apr_file_inherit_set() on the dupped 
+     * apr_file_t when desired.
+     */
+    (*new_file)->flags = old_file->flags
+                       & ~(APR_INHERIT | APR_FILE_NOCLEANUP);
+
     apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
                               apr_unix_file_cleanup, 
-                              ((*new_file)->flags & APR_INHERIT)
-                                 ? apr_pool_cleanup_null
-                                 : apr_unix_file_cleanup);
+                              apr_unix_file_cleanup);
 
     return APR_SUCCESS;
 }
@@ -147,14 +151,6 @@
 APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
                                         apr_file_t *old_file, apr_pool_t *p)
 {
-    /* an existing apr_file_t may already be closed, and therefore
-     * have no cleanup remaining; but we don't want to double-register
-     * the same cleanup in _file_dup.  Kill the existing cleanup before
-     * invoking _file_dup to the existing new_file.
-     */
-    apr_pool_cleanup_kill(new_file->pool, (void *)(new_file),
-                          apr_unix_file_cleanup);
-
     return _file_dup(&new_file, old_file, p, 2);
 }
 


Reply via email to