Bug 1240160: Add the TimeStamp based uptime value to crash reports, tagging it as UptimeTS, to differentiate from an existing Uptime value. A bit of additional code, avoiding the usage of C libraries to format some strings and a way to gtest these. r=benwa, also carrying ted.mielczarek review for the exception handler changes. draft
authorMilan Sreckovic <milan@mozilla.com>
Wed, 17 Feb 2016 17:44:21 -0500
changeset 331691 1f5d5137b3b99326e460da185074cedd2b04a2ad
parent 331542 709f559b5406e8555cf84dd09bdc747b076f142c
child 331707 5b0ebb8e9fb37f40a86cd5d6547f6bfa1bae1a47
push id11038
push usermsreckovic@mozilla.com
push dateWed, 17 Feb 2016 22:45:03 +0000
reviewersbenwa, also
bugs1240160
milestone47.0a1
Bug 1240160: Add the TimeStamp based uptime value to crash reports, tagging it as UptimeTS, to differentiate from an existing Uptime value. A bit of additional code, avoiding the usage of C libraries to format some strings and a way to gtest these. r=benwa, also carrying ted.mielczarek review for the exception handler changes. MozReview-Commit-ID: 12pRuD7agIG
gfx/tests/gtest/TestGfxPrefs.cpp
toolkit/crashreporter/nsExceptionHandler.cpp
--- a/gfx/tests/gtest/TestGfxPrefs.cpp
+++ b/gfx/tests/gtest/TestGfxPrefs.cpp
@@ -74,8 +74,33 @@ TEST(GfxPrefs, Set) {
 
   // Once float, default -1
   ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == -1.0f);
   gfxPrefs::SetAPZMaxVelocity(1.75f);
   ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == 1.75f);
   gfxPrefs::SetAPZMaxVelocity(-1.0f);
   ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == -1.0f);
 }
+
+#ifdef MOZ_CRASHREPORTER
+// Randomly test the function we use in nsExceptionHandler.cpp here:
+extern bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength);
+TEST(GfxPrefs, StringUtility)
+{
+  char testBuffer[64];
+  double testVal[] = {13.4,
+                      3324243.42,
+                      0.332424342,
+                      864.0,
+                      86400 * 100000000.0 * 10000000000.0 * 10000000000.0 * 100.0,
+                      86400.0 * 366.0 * 100.0 + 14243.44332};
+  for (size_t i=0; i<mozilla::ArrayLength(testVal); i++) {
+    ASSERT_TRUE(SimpleNoCLibDtoA(testVal[i], testBuffer, sizeof(testBuffer)));
+    ASSERT_TRUE(fabs(1.0 - atof(testBuffer)/testVal[i]) < 0.0001);
+  }
+
+  // We do not like negative numbers (random limitation)
+  ASSERT_FALSE(SimpleNoCLibDtoA(-864.0, testBuffer, sizeof(testBuffer)));
+
+  // It won't fit into 32:
+  ASSERT_FALSE(SimpleNoCLibDtoA(testVal[4], testBuffer, sizeof(testBuffer)/2));
+}
+#endif
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -8,16 +8,17 @@
 #include "nsDataHashtable.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/CrashReporterChild.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "mozilla/unused.h"
 #include "mozilla/Snprintf.h"
 #include "mozilla/SyncRunnable.h"
+#include "mozilla/TimeStamp.h"
 
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "jsfriendapi.h"
 
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
@@ -82,16 +83,17 @@ using mozilla::InjectCrashRunnable;
 #include "mozilla/Mutex.h"
 #include "nsDebug.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "prprf.h"
 #include <map>
 #include <vector>
 
+#include "mozilla/double-conversion.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/mozalloc_oom.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
 #if defined(XP_MACOSX)
 CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
@@ -406,16 +408,67 @@ typedef struct {
   std::string name;
   uintptr_t   start_address;
   size_t      length;
   size_t      file_offset;
 } mapping_info;
 static std::vector<mapping_info> library_mappings;
 typedef std::map<uint32_t,google_breakpad::MappingList> MappingMap;
 #endif
+}
+
+// Format a non-negative double to a string, without using C-library functions,
+// which need to be avoided (.e.g. bug 1240160, comment 10).  Leave the utility
+// non-file static so that we can gtest it.  Return false if we failed to
+// get the formatting done correctly.
+bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength)
+{
+  // aBufferLength is the size of the buffer.  Be paranoid.
+  aBuffer[aBufferLength-1] = '\0';
+
+  if (aValue < 0) {
+    return false;
+  }
+
+  int length, point, i;
+  bool sign;
+  bool ok = true;
+  double_conversion::DoubleToStringConverter::DoubleToAscii(
+                                     aValue,
+                                     double_conversion::DoubleToStringConverter::SHORTEST,
+                                     8,
+                                     aBuffer,
+                                     aBufferLength,
+                                     &sign,
+                                     &length,
+                                     &point);
+
+  // length does not account for the 0 terminator.
+  if (length > point && (length+1) < (aBufferLength-1)) {
+    // We have to insert a decimal point.  Not worried about adding a leading zero
+    // in the < 1 (point == 0) case.
+    aBuffer[length+1] = '\0';
+    for (i=length; i>point; i-=1) {
+      aBuffer[i] = aBuffer[i-1];
+    }
+    aBuffer[i] = '.'; // Not worried about locales
+  } else if (length < point) {
+    // Trailing zeros scenario
+    for (i=length; i<point; i+=1) {
+      if (i >= aBufferLength-2) {
+        ok = false;
+      }
+      aBuffer[i] = '0';
+    }
+    aBuffer[i] = '\0';
+  }
+  return ok;
+}
+
+namespace CrashReporter {
 
 #ifdef XP_LINUX
 inline void
 my_inttostring(intmax_t t, char* buffer, size_t buffer_length)
 {
   my_memset(buffer, 0, buffer_length);
   my_uitos(buffer, t, my_uint_len(t));
 }
@@ -749,16 +802,22 @@ bool MinidumpCallback(
     XP_TTOA(timeSinceLastCrash, timeSinceLastCrashString, 10);
   }
   // write crash time to file
   if (lastCrashTimeFilename[0] != 0) {
     PlatformWriter lastCrashFile(lastCrashTimeFilename);
     WriteString(lastCrashFile, crashTimeString);
   }
 
+  bool ignored = false;
+  double uptimeTS = (TimeStamp::NowLoRes()-
+                     TimeStamp::ProcessCreation(ignored)).ToSecondsSigDigits();
+  char uptimeTSString[64];
+  SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString));
+
   // Write crash event file.
 
   // Minidump IDs are UUIDs (36) + NULL.
   static char id_ascii[37];
 #ifdef XP_LINUX
   const char * index = strrchr(descriptor.path(), '/');
   MOZ_ASSERT(index);
   MOZ_ASSERT(strlen(index) == 1 + 36 + 4); // "/" + UUID + ".dmp"
@@ -800,16 +859,18 @@ bool MinidumpCallback(
     }
 
     if (!crashReporterAPIData->IsEmpty()) {
       // write out API data
       apiData.Open(extraDataPath);
       apiData.WriteBuffer(crashReporterAPIData->get(), crashReporterAPIData->Length());
     }
     WriteAnnotation(apiData, "CrashTime", crashTimeString);
+    WriteAnnotation(apiData, "UptimeTS", uptimeTSString);
+
     if (timeSinceLastCrash != 0) {
       WriteAnnotation(apiData, "SecondsSinceLastCrash",
                       timeSinceLastCrashString);
       WriteAnnotation(eventFile, "SecondsSinceLastCrash",
                       timeSinceLastCrashString);
     }
     if (isGarbageCollecting) {
       WriteAnnotation(apiData, "IsGarbageCollecting",
@@ -2589,16 +2650,26 @@ WriteExtraData(nsIFile* extraFile,
   if (writeCrashTime) {
     time_t crashTime = time(nullptr);
     char crashTimeString[32];
     XP_TTOA(crashTime, crashTimeString, 10);
 
     WriteAnnotation(fd,
                     nsDependentCString("CrashTime"),
                     nsDependentCString(crashTimeString));
+
+    bool ignored = false;
+    double uptimeTS = (TimeStamp::NowLoRes()-
+                       TimeStamp::ProcessCreation(ignored)).ToSecondsSigDigits();
+    char uptimeTSString[64];
+    SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString));
+
+    WriteAnnotation(fd,
+                    nsDependentCString("UptimeTS"),
+                    nsDependentCString(uptimeTSString));
   }
 
   PR_Close(fd);
   return true;
 }
 
 bool
 AppendExtraData(nsIFile* extraFile, const AnnotationTable& data)