Bug 827749 - Aggressively duplicate file descriptors. r=cjones.
☠☠ backed out by e06f05ff1edc ☠ ☠
authorBen Turner <bent.mozilla@gmail.com>
Thu, 10 Jan 2013 13:00:17 +0100
changeset 118712 f3b6bc4b25904d62588fd33ba347741872b7fc2d
parent 118711 645bf43f8f14776742275589b72bda9fbb466fa5
child 118713 9a93bc7b059bf7f97ccb412cea5f04e5c8415f1d
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerscjones
bugs827749
milestone21.0a1
Bug 827749 - Aggressively duplicate file descriptors. r=cjones.
ipc/glue/FileDescriptor.cpp
ipc/glue/FileDescriptor.h
--- a/ipc/glue/FileDescriptor.cpp
+++ b/ipc/glue/FileDescriptor.cpp
@@ -3,60 +3,103 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileDescriptor.h"
 
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
 
 #ifdef XP_WIN
+
 #include <windows.h>
 #define INVALID_HANDLE INVALID_HANDLE_VALUE
-#else
+
+#else // XP_WIN
+
 #include <unistd.h>
+
+#ifndef OS_POSIX
+#define OS_POSIX
+#endif
+
+#include "base/eintr_wrapper.h"
 #define INVALID_HANDLE -1
-#endif
+
+#endif // XP_WIN
 
 using mozilla::ipc::FileDescriptor;
 
 FileDescriptor::FileDescriptor()
-: mHandle(INVALID_HANDLE)
+: mHandle(INVALID_HANDLE), mMustCloseHandle(false)
 { }
 
+FileDescriptor::FileDescriptor(PlatformHandleType aHandle)
+: mHandle(INVALID_HANDLE), mMustCloseHandle(false)
+{
+  DuplicateInCurrentProcess(aHandle);
+}
+
+FileDescriptor::~FileDescriptor()
+{
+  if (mMustCloseHandle) {
+    MOZ_ASSERT(mHandle != INVALID_HANDLE);
+#ifdef XP_WIN
+    if (!CloseHandle(mHandle)) {
+      NS_WARNING("Failed to close file handle!");
+    }
+#else // XP_WIN
+    HANDLE_EINTR(close(mHandle));
+#endif
+  }
+}
+
+void
+FileDescriptor::DuplicateInCurrentProcess(PlatformHandleType aHandle)
+{
+  if (aHandle != INVALID_HANDLE) {
+    PlatformHandleType newHandle;
+#ifdef XP_WIN
+    if (DuplicateHandle(GetCurrentProcess(), aHandle, GetCurrentProcess(),
+                        &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+#else // XP_WIN
+    if ((newHandle = dup(aHandle)) != INVALID_HANDLE) {
+#endif
+      mHandle = newHandle;
+      mMustCloseHandle = true;
+      return;
+    }
+    NS_WARNING("Failed to duplicate file descriptor!");
+  }
+
+  mHandle = INVALID_HANDLE;
+  mMustCloseHandle = false;
+}
+
 FileDescriptor::PickleType
 FileDescriptor::ShareTo(const FileDescriptor::IPDLPrivate&,
                         FileDescriptor::ProcessHandle aOtherProcess) const
 {
+  PlatformHandleType newHandle;
 #ifdef XP_WIN
-  if (mHandle == INVALID_HANDLE) {
-    return INVALID_HANDLE;
+  if (mHandle != INVALID_HANDLE) {
+    if (DuplicateHandle(GetCurrentProcess(), mHandle, aOtherProcess,
+                        &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+      // mHandle must still be closed here (since it is an in-process handle
+      // that we duplicated) so leave mMustCloseHandle unchanged.
+      return newHandle;
+    }
+    NS_WARNING("Failed to duplicate file handle!");
   }
-
-  PlatformHandleType newHandle;
-  if (!DuplicateHandle(GetCurrentProcess(), mHandle, aOtherProcess, &newHandle,
-                       0, FALSE, DUPLICATE_SAME_ACCESS)) {
-    NS_WARNING("Failed to duplicate file handle!");
-    return INVALID_HANDLE;
-  }
-
-  return newHandle;
+  return INVALID_HANDLE;
 #else // XP_WIN
-  if (mHandle == INVALID_HANDLE) {
-    return base::FileDescriptor();
+  if (mHandle != INVALID_HANDLE) {
+    newHandle = dup(mHandle);
+    return base::FileDescriptor(newHandle, /* auto_close */ true);
   }
-
-  PlatformHandleType newHandle = dup(mHandle);
-  if (newHandle < 0) {
-    NS_WARNING("Failed to duplicate file descriptor!");
-    return base::FileDescriptor();
-  }
-
-  // This file descriptor must be closed once the caller is done using it, so
-  // pass true here for the 'auto_close' argument.
-  return base::FileDescriptor(newHandle, true);
+  return base::FileDescriptor();
 #endif
 
   MOZ_NOT_REACHED("Must not get here!");
   return PickleType();
 }
 
 bool
 FileDescriptor::IsValid() const
--- a/ipc/glue/FileDescriptor.h
+++ b/ipc/glue/FileDescriptor.h
@@ -45,28 +45,40 @@ public:
 #endif
 
   // This should only ever be created by IPDL.
   struct IPDLPrivate
   {};
 
   FileDescriptor();
 
-  FileDescriptor(PlatformHandleType aHandle)
-  : mHandle(aHandle)
-  { }
+  FileDescriptor(const FileDescriptor& aOther)
+  {
+    *this = aOther;
+  }
+
+  FileDescriptor(PlatformHandleType aHandle);
 
   FileDescriptor(const IPDLPrivate&, const PickleType& aPickle)
 #ifdef XP_WIN
-  : mHandle(aPickle)
+  : mHandle(aPickle), mMustCloseHandle(false)
 #else
-  : mHandle(aPickle.fd)
+  : mHandle(aPickle.fd), mMustCloseHandle(false)
 #endif
   { }
 
+  ~FileDescriptor();
+
+  FileDescriptor&
+  operator=(const FileDescriptor& aOther)
+  {
+    DuplicateInCurrentProcess(aOther.mHandle);
+    return *this;
+  }
+
   // Performs platform-specific actions to duplicate mHandle in the other
   // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a
   // pickled value that can be passed to the other process via IPC.
   PickleType
   ShareTo(const IPDLPrivate&, ProcessHandle aOtherProcess) const;
 
   // Tests mHandle against a well-known invalid platform-specific file handle
   // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows).
@@ -81,15 +93,19 @@ public:
 
   bool
   operator==(const FileDescriptor& aOther) const
   {
     return mHandle == aOther.mHandle;
   }
 
 private:
+  void
+  DuplicateInCurrentProcess(PlatformHandleType aHandle);
+
   PlatformHandleType mHandle;
+  bool mMustCloseHandle;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_FileDescriptor_h