Bug 1296756 - Record number of open file descriptors in crash report. r=billm,ted draft
authorKan-Ru Chen <kanru@kanru.info>
Fri, 26 Aug 2016 18:31:21 +0800
changeset 406077 98eb0d08f8ab1525ff5c49883f10055ec6cb947a
parent 405855 a551f534773cf2d6933f78ce7d82a7a33a99643e
child 529573 8be2a4b68db9443046c76edc311d109e23b2ffac
push id27635
push userbmo:kchen@mozilla.com
push dateFri, 26 Aug 2016 10:35:43 +0000
reviewersbillm, ted
bugs1296756
milestone51.0a1
Bug 1296756 - Record number of open file descriptors in crash report. r=billm,ted Currently only implemented for Mac and Linux. The recorded information looks like "OpenedFileDescriptors: 74 22 0 28 0 0 8 10 6". MozReview-Commit-ID: oasok2JDUw
ipc/chromium/src/chrome/common/ipc_channel_posix.cc
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -34,16 +34,20 @@
 #include "chrome/common/ipc_message_utils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 
 #ifdef MOZ_FAULTY
 #include "mozilla/ipc/Faulty.h"
 #endif
 
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#endif
+
 // Work around possible OS limitations.
 static const size_t kMaxIOVecSize = 256;
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracerImpl.h"
 using namespace mozilla::tasktracer;
 #endif
 
@@ -166,16 +170,19 @@ bool SetCloseOnExec(int fd) {
 //------------------------------------------------------------------------------
 
 Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
                                   Listener* listener)
     : factory_(this) {
   Init(mode, listener);
 
   if (!CreatePipe(channel_id, mode)) {
+#ifdef MOZ_CRASHREPORTER
+    CrashReporter::AnnotateOpenedFileDescriptors();
+#endif
     // The pipe may have been closed already.
     CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
                              "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
                              " mode error(" << strerror(errno) << ").";
   }
 }
 
 Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
@@ -477,16 +484,19 @@ bool Channel::ChannelImpl::ProcessIncomi
 
         if (m.header()->num_fds >
             FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
           // There are too many descriptors in this message
           error = "Message requires an excessive number of descriptors";
         }
 
         if (error) {
+#ifdef MOZ_CRASHREPORTER
+          CrashReporter::AnnotateOpenedFileDescriptors();
+#endif
           CHROMIUM_LOG(WARNING) << error
                                 << " channel:" << this
                                 << " message-type:" << m.type()
                                 << " header()->num_fds:" << m.header()->num_fds
                                 << " num_fds:" << num_fds
                                 << " fds_i:" << fds_i;
           // close the existing file descriptors so that we don't leak them
           for (unsigned i = fds_i; i < num_fds; ++i)
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -44,30 +44,32 @@
 #include "client/mac/handler/exception_handler.h"
 #include <string>
 #include <Carbon/Carbon.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <crt_externs.h>
 #include <fcntl.h>
 #include <mach/mach.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <spawn.h>
 #include <unistd.h>
 #include "mac_utils.h"
 #elif defined(XP_LINUX)
 #include "nsIINIParser.h"
 #include "common/linux/linux_libc_support.h"
 #include "third_party/lss/linux_syscall_support.h"
 #include "client/linux/crash_generation/client_info.h"
 #include "client/linux/crash_generation/crash_generation_server.h"
 #include "client/linux/handler/exception_handler.h"
 #include "common/linux/eintr_wrapper.h"
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #elif defined(XP_SOLARIS)
 #include "client/solaris/handler/exception_handler.h"
 #include <fcntl.h>
 #include <sys/types.h>
 #include <unistd.h>
 #else
 #error "Not yet implemented for this platform"
@@ -2130,16 +2132,88 @@ public:
   NS_IMETHOD Run() override;
 
 private:
   nsCString mKey;
   nsCString mData;
   bool mAppendAppNotes;
 };
 
+enum FileDescriptorType {
+  kFileSocket,
+  kFileLink,
+  kFileRegular,
+  kFileBlock,
+  kFileDirectory,
+  kFileCharacter,
+  kFileFifo,
+  kFileUnknown,
+  kFileTotal
+};
+
+void AnnotateOpenedFileDescriptors()
+{
+#if defined(XP_MAC) || defined(XP_LINUX)
+  // Get maximum number of FDs we can create
+  int maxFds = getdtablesize();
+  if (maxFds < 0) {
+    // It's unlikely that getdtablesize() can fail. Make a best guess.
+    maxFds = 65536;
+  }
+  // Iterate and check if they are open
+  int numFds[kFileTotal] = {0};
+  int total = 0;
+  struct stat sb;
+  int ok;
+  for (int i = 0; i < maxFds; ++i) {
+    ok = fstat(i, &sb);
+    if (ok == 0) {
+      switch (sb.st_mode & S_IFMT) {
+        case S_IFSOCK:
+          numFds[kFileSocket]++;
+          break;
+        case S_IFLNK:
+          numFds[kFileLink]++;
+          break;
+        case S_IFREG:
+          numFds[kFileRegular]++;
+          break;
+        case S_IFBLK:
+          numFds[kFileBlock]++;
+          break;
+        case S_IFDIR:
+          numFds[kFileDirectory]++;
+          break;
+        case S_IFCHR:
+          numFds[kFileCharacter]++;
+          break;
+        case S_IFIFO:
+          numFds[kFileFifo]++;
+          break;
+        default:
+          numFds[kFileUnknown]++;
+          break;
+      }
+      total++;
+    }
+  }
+  // Generate report
+  nsAutoCString report;
+  report.AppendInt(total);
+  for (int i = 0; i < int(kFileTotal); ++i) {
+    report += " ";
+    report.AppendInt(numFds[i]);
+  }
+  AnnotateCrashReport(NS_LITERAL_CSTRING("OpenedFileDescriptors"), report);
+#ifdef DEBUG
+  printf_stderr("OpenedFileDescriptors: %s\n", report.BeginReading());
+#endif
+#endif
+}
+
 nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
 {
   if (!GetEnabled())
     return NS_ERROR_NOT_INITIALIZED;
 
   bool isParentProcess = XRE_IsParentProcess();
   if (!isParentProcess && !NS_IsMainThread()) {
     // Child process needs to handle this in the main thread:
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -75,16 +75,18 @@ nsresult AppendAppNotesToCrashReport(con
 
 // NOTE: If you change this definition, also change the definition in Assertions.h
 // as it is intended to be defining this same function.
 void AnnotateMozCrashReason(const char* aReason);
 void AnnotateOOMAllocationSize(size_t size);
 nsresult SetGarbageCollecting(bool collecting);
 void SetEventloopNestingLevel(uint32_t level);
 
+void AnnotateOpenedFileDescriptors();
+
 void AnnotateTexturesSize(size_t size);
 
 nsresult SetRestartArgs(int argc, char** argv);
 nsresult SetupExtraData(nsIFile* aAppDataDirectory,
                         const nsACString& aBuildID);
 bool GetLastRunCrashID(nsAString& id);
 
 // Registers an additional memory region to be included in the minidump