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
--- 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