Bug 1500703 - Include more context when reporting recording mismatches, r=mccr8.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 26 Nov 2018 12:42:28 -1000
changeset 507407 b12b2142017abdb8cce3ea9758ed0af16c398e15
parent 507406 b9f41dd78cfdd2739b343595c1647ef1c4f57875
child 507408 47750e022e23d5b4eb445443a737a04ba9b45391
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1500703
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1500703 - Include more context when reporting recording mismatches, r=mccr8.
toolkit/recordreplay/File.cpp
toolkit/recordreplay/File.h
toolkit/recordreplay/ProcessRecordReplay.cpp
toolkit/recordreplay/ProcessRedirectDarwin.cpp
--- a/toolkit/recordreplay/File.cpp
+++ b/toolkit/recordreplay/File.cpp
@@ -154,18 +154,27 @@ Stream::WriteScalar(size_t aValue)
 void
 Stream::RecordOrReplayThreadEvent(ThreadEvent aEvent)
 {
   if (IsRecording()) {
     WriteScalar((size_t) aEvent);
   } else {
     ThreadEvent oldEvent = (ThreadEvent) ReadScalar();
     if (oldEvent != aEvent) {
-      child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s Replayed %s",
-                              ThreadEventName(oldEvent), ThreadEventName(aEvent));
+      const char* extra = "";
+      if (oldEvent == ThreadEvent::Assert) {
+        // Include the asserted string in the error. This must match up with
+        // the writes in RecordReplayAssert.
+        if (mNameIndex == MainThreadId) {
+          (void) ReadScalar(); // For the ExecutionProgressCounter write below.
+        }
+        extra = ReadInputString();
+      }
+      child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s %s Replayed %s",
+                              ThreadEventName(oldEvent), extra, ThreadEventName(aEvent));
     }
     mLastEvent = aEvent;
   }
 
   // Check the execution progress counter for events executing on the main thread.
   if (mNameIndex == MainThreadId) {
     CheckInput(*ExecutionProgressCounter());
   }
@@ -180,32 +189,38 @@ Stream::CheckInput(size_t aValue)
     size_t oldValue = ReadScalar();
     if (oldValue != aValue) {
       child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %llu Replayed %llu",
                               ThreadEventName(mLastEvent), oldValue, aValue);
     }
   }
 }
 
+const char*
+Stream::ReadInputString()
+{
+  size_t len = ReadScalar();
+  EnsureInputBallast(len + 1);
+  ReadBytes(mInputBallast.get(), len);
+  mInputBallast[len] = 0;
+  return mInputBallast.get();
+}
+
 void
 Stream::CheckInput(const char* aValue)
 {
   size_t len = strlen(aValue);
   if (IsRecording()) {
     WriteScalar(len);
     WriteBytes(aValue, len);
   } else {
-    size_t oldLen = ReadScalar();
-    EnsureInputBallast(oldLen + 1);
-    ReadBytes(mInputBallast.get(), oldLen);
-    mInputBallast[oldLen] = 0;
-
-    if (len != oldLen || memcmp(aValue, mInputBallast.get(), len) != 0) {
+    const char* oldInput = ReadInputString();
+    if (strcmp(oldInput, aValue) != 0) {
       child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %s Replayed %s",
-                              ThreadEventName(mLastEvent), mInputBallast.get(), aValue);
+                              ThreadEventName(mLastEvent), oldInput, aValue);
     }
   }
 }
 
 void
 Stream::CheckInput(const void* aData, size_t aSize)
 {
   CheckInput(aSize);
--- a/toolkit/recordreplay/File.h
+++ b/toolkit/recordreplay/File.h
@@ -192,16 +192,17 @@ private:
     DontCopyExistingData,
     CopyExistingData
   };
 
   void EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize, size_t aNeededSize, size_t aMaxSize,
                     ShouldCopy aCopy);
   void EnsureInputBallast(size_t aSize);
   void Flush(bool aTakeLock);
+  const char* ReadInputString();
 
   static size_t BallastMaxSize();
 };
 
 class File
 {
 public:
   enum Mode {
--- a/toolkit/recordreplay/ProcessRecordReplay.cpp
+++ b/toolkit/recordreplay/ProcessRecordReplay.cpp
@@ -350,16 +350,18 @@ RecordReplayInterface_InternalRecordRepl
   if (!res.CanAccessEvents()) {
     return;
   }
 
   // Add the asserted string to the recording.
   char text[1024];
   VsprintfLiteral(text, aFormat, aArgs);
 
+  // This must be kept in sync with Stream::RecordOrReplayThreadEvent, which
+  // peeks at the input string written after the thread event.
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Assert);
   thread->Events().CheckInput(text);
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRecordReplayAssertBytes(const void* aData, size_t aSize)
 {
   Thread* thread = Thread::Current();
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -901,16 +901,19 @@ Preamble_getenv(CallArguments* aArgument
 
   // The JPEG library can fetch configuration information from the environment
   // in a way that can run non-deterministically on different threads.
   if (strncmp(env, "JSIMD_", 6) == 0) {
     aArguments->Rval<char*>() = nullptr;
     return PreambleResult::Veto;
   }
 
+  // Include the environment variable being checked in an assertion, to make it
+  // easier to debug recording mismatches involving getenv.
+  RecordReplayAssert("getenv %s", env);
   return PreambleResult::Redirect;
 }
 
 static struct tm gGlobalTM;
 
 // localtime behaves the same as localtime_r, except it is not reentrant.
 // For simplicity, define this in terms of localtime_r.
 static PreambleResult