Bug 1608158 - Include MainThreadRunnableName in crash reports, r=chutten,gsvelto draft
authorNika Layzell <nika@thelayzells.com>
Thu, 16 Jan 2020 18:33:26 +0000
changeset 2598870 f30b36524a7345872f59f5bd57dcb2344bcc6dd0
parent 2598325 7e0886a94d70b8696d6fc0481d9f9ae12b85c41a
child 2598871 276f2ad3c7dc7d1a115efdc2e6b0a06bc352f422
push id476911
push userreviewbot
push dateThu, 16 Jan 2020 18:33:46 +0000
treeherdertry@276f2ad3c7dc [default view] [failures only]
reviewerschutten, gsvelto
bugs1608158
milestone74.0a1
Bug 1608158 - Include MainThreadRunnableName in crash reports, r=chutten,gsvelto While this information is often included in crash stacks, there are a few situations where this probe can give us better information: * Sometimes we get absolute garbage for part of the stack, and having information off to the side could help clarify things. * Sometimes many different runnables get their Run() method merged through code folding, and so the Run() you see in the stack is very much not what you would expect to see. Having the runnable name be available could help clarify things. * This data may be easier to work with in bulk as it is a separate, well-defined, field. Differential Revision: https://phabricator.services.mozilla.com/D59364 Differential Diff: PHID-DIFF-pfjuitljy4yndakpm663
toolkit/components/telemetry/docs/data/crash-ping.rst
toolkit/crashreporter/CrashAnnotations.yaml
toolkit/crashreporter/nsExceptionHandler.cpp
--- a/toolkit/components/telemetry/docs/data/crash-ping.rst
+++ b/toolkit/components/telemetry/docs/data/crash-ping.rst
@@ -69,16 +69,17 @@ Structure:
           SystemMemoryUsePercentage: <percentage>, // Windows-only, percent of memory in use
           StartupCrash: "1", // Optional, if set indicates that Firefox crashed during startup
           TextureUsage: <usage>, // Optional, usage of texture memory in bytes
           TotalPageFile: <size>, // Windows-only, paging file in use expressed in bytes
           TotalPhysicalMemory: <size>, // Windows-only, physical memory in use expressed in bytes
           TotalVirtualMemory: <size>, // Windows-only, virtual memory in use expressed in bytes
           UptimeTS: <duration>, // Seconds since Firefox was started, this can have a fractional component
           User32BeforeBlocklist: "1", // Windows-only, present only if user32.dll was loaded before the DLL blocklist has been initialized
+          MainThreadRunnableName: <name>, // Optional, Nightly-only, name of the currently executing nsIRunnable on the main thread
         },
         hasCrashEnvironment: bool
       }
     }
 
 .. note::
 
   For "crash" pings generated by the crashreporter we are deliberately truncating the ``creationTime``
--- a/toolkit/crashreporter/CrashAnnotations.yaml
+++ b/toolkit/crashreporter/CrashAnnotations.yaml
@@ -595,16 +595,22 @@ LocalStorageShutdownTimeout:
 
 LowCommitSpaceEvents:
   description: >
     Number of times the available memory tracker has detected a that
     commit-space was running low. This is a Windows-specific annotation.
   type: integer
   ping: true
 
+MainThreadRunnableName:
+  description: >
+    Name of the currently executing nsIRunnable on the main thread.
+  type: string
+  ping: true
+
 MarshalActCtxManifestPath:
   description: >
     Proxy stream marshalling current activation context manifest path.
   type: string
 
 MemoryErrorCorrection:
   description: >
     Windows only, type of error correction used by system memory.  See
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/Printf.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 
 #include "nsThreadUtils.h"
+#include "nsThread.h"
 #include "jsfriendapi.h"
 #include "ThreadAnnotation.h"
 #include "private/pprio.h"
 
 #if defined(XP_WIN)
 #  ifdef WIN32_LEAN_AND_MEAN
 #    undef WIN32_LEAN_AND_MEAN
 #  endif
@@ -128,16 +129,17 @@ namespace CrashReporter {
 
 #ifdef XP_WIN
 typedef wchar_t XP_CHAR;
 typedef std::wstring xpstring;
 #  define XP_TEXT(x) L##x
 #  define CONVERT_XP_CHAR_TO_UTF16(x) x
 #  define XP_STRLEN(x) wcslen(x)
 #  define my_strlen strlen
+#  define my_memchr memchr
 #  define CRASH_REPORTER_FILENAME "crashreporter.exe"
 #  define XP_PATH_SEPARATOR L"\\"
 #  define XP_PATH_SEPARATOR_CHAR L'\\'
 #  define XP_PATH_MAX (MAX_PATH + 1)
 // "<reporter path>" "<minidump path>"
 #  define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
 #  ifdef _USE_32BIT_TIME_T
 #    define XP_TTOA(time, buffer) ltoa(time, buffer, 10)
@@ -158,16 +160,17 @@ typedef std::string xpstring;
 #    define XP_STRLEN(x) my_strlen(x)
 #    define XP_TTOA(time, buffer) my_inttostring(time, buffer, sizeof(buffer))
 #    define XP_STOA(size, buffer) my_inttostring(size, buffer, sizeof(buffer))
 #  else
 #    define XP_STRLEN(x) strlen(x)
 #    define XP_TTOA(time, buffer) sprintf(buffer, "%ld", time)
 #    define XP_STOA(size, buffer) sprintf(buffer, "%zu", (size_t)size)
 #    define my_strlen strlen
+#    define my_memchr memchr
 #    define sys_close close
 #    define sys_fork fork
 #    define sys_open open
 #    define sys_read read
 #    define sys_write write
 #  endif
 #endif  // XP_WIN
 
@@ -1271,16 +1274,38 @@ static bool LaunchCrashHandlerService(XP
     Unused << HANDLE_EINTR(sys_waitpid(pid, &status, __WALL));
   }
 
   return true;
 }
 
 #endif
 
+static void WriteMainThreadRunnableName(AnnotationWriter& aWriter) {
+#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
+  // Only try to collect this information if the main thread is crashing.
+  if (!NS_IsMainThread()) {
+    return;
+  }
+
+  // NOTE: Use `my_memchr` over `strlen` to ensure we don't run off the end of
+  // the buffer if it contains no null bytes. This is used instead of `strnlen`,
+  // as breakpad's linux support library doesn't export a `my_strnlen` function.
+  const char* buf = nsThread::sMainThreadRunnableName.begin();
+  size_t len = nsThread::kRunnableNameBufSize;
+  if (void* end = my_memchr(buf, '\0', len)) {
+    len = static_cast<const char*>(end) - buf;
+  }
+
+  if (len > 0) {
+    aWriter.Write(Annotation::MainThreadRunnableName, buf, len);
+  }
+#endif
+}
+
 static void WriteMozCrashReason(AnnotationWriter& aWriter) {
   if (gMozCrashReason != nullptr) {
     aWriter.Write(Annotation::MozCrashReason, gMozCrashReason);
   }
 }
 
 static void WriteAnnotationsForMainProcessCrash(PlatformWriter& pw,
                                                 const phc::AddrInfo* addrInfo,
@@ -1339,16 +1364,18 @@ static void WriteAnnotationsForMainProce
 #  ifdef HAS_DLL_BLOCKLIST
   // HACK: The DLL blocklist code will manually write its annotations as JSON
   DllBlocklist_WriteNotes(writer);
 #  endif
 #endif  // XP_WIN
 
   WriteMozCrashReason(writer);
 
+  WriteMainThreadRunnableName(writer);
+
   char oomAllocationSizeBuffer[32] = "";
   if (gOOMAllocationSize) {
     XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer);
     writer.Write(Annotation::OOMAllocationSize, oomAllocationSizeBuffer);
   }
 
   char texturesSizeBuffer[32] = "";
   if (gTexturesSize) {
@@ -1640,16 +1667,18 @@ static void PrepareChildExceptionTimeAnn
   char oomAllocationSizeBuffer[32] = "";
   if (gOOMAllocationSize) {
     XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer);
     writer.Write(Annotation::OOMAllocationSize, oomAllocationSizeBuffer);
   }
 
   WriteMozCrashReason(writer);
 
+  WriteMainThreadRunnableName(writer);
+
 #ifdef MOZ_PHC
   WritePHCAddrInfo(writer, addrInfo);
 #endif
 
   std::function<void(const char*)> getThreadAnnotationCB =
       [&](const char* aValue) -> void {
     if (aValue) {
       writer.Write(Annotation::ThreadIdNameMapping, aValue);