GS cookie check fix for debugger stackwalks port
authorJuan Sebastian Hoyos Ayala <juan.hoyos@microsoft.com>
Mon, 9 Jul 2018 21:28:57 +0000 (14:28 -0700)
committerJuan Sebastian Hoyos Ayala <juan.hoyos@microsoft.com>
Tue, 10 Jul 2018 17:36:19 +0000 (10:36 -0700)
This bug fix is a port from the equivalent fix in framework. The
debugger tried performing a stackwalk in the epilog due to the JIT
incorrectly reporting epilogue information. This caused an invalid
GS cookie to be checked and caused the debugger to crash. A flag was
added to allow debug stackwalks to skip the cookie check.

Commit migrated from https://github.com/dotnet/coreclr/commit/32741b9e97f901242394dfc682c228a5d810f454

src/coreclr/src/debug/daccess/dacimpl.h
src/coreclr/src/debug/ee/debugger.cpp
src/coreclr/src/debug/ee/frameinfo.cpp
src/coreclr/src/vm/stackwalk.cpp
src/coreclr/src/vm/threads.h

index 2647c8d..6147de3 100644 (file)
@@ -2005,7 +2005,7 @@ private:
         mCurr = &mHead;
         
         // Walk the stack, set mEnumerated to true to ensure we don't do it again.
-        unsigned int flagsStackWalk = ALLOW_INVALID_OBJECTS|ALLOW_ASYNC_STACK_WALK;
+        unsigned int flagsStackWalk = ALLOW_INVALID_OBJECTS|ALLOW_ASYNC_STACK_WALK|SKIP_GSCOOKIE_CHECK;
 #if defined(WIN64EXCEPTIONS)
         flagsStackWalk |= GC_FUNCLET_REFERENCE_REPORTING;
 #endif // defined(WIN64EXCEPTIONS)
index 2ca8762..a8d590e 100644 (file)
@@ -12588,7 +12588,7 @@ bool Debugger::IsThreadAtSafePlaceWorker(Thread *thread)
                                  Debugger::AtSafePlaceStackWalkCallback,
                                  (VOID*)(&atSafePlace),
                                  QUICKUNWIND | HANDLESKIPPEDFRAMES |
-                                 DISABLE_MISSING_FRAME_DETECTION);
+                                 DISABLE_MISSING_FRAME_DETECTION | SKIP_GSCOOKIE_CHECK);
 
 #ifdef LOGGING
     if (!atSafePlace)
index 0387ca9..f8f8932 100644 (file)
@@ -2141,7 +2141,9 @@ StackWalkAction DebuggerWalkStack(Thread *thread,
 
         result = g_pEEInterface->StackWalkFramesEx(thread, &data.regDisplay,
                                                    DebuggerWalkStackProc,
-                                                   &data, flags | HANDLESKIPPEDFRAMES | NOTIFY_ON_U2M_TRANSITIONS | ALLOW_ASYNC_STACK_WALK);
+                                                   &data,
+                                                   flags | HANDLESKIPPEDFRAMES | NOTIFY_ON_U2M_TRANSITIONS |
+                                                   ALLOW_ASYNC_STACK_WALK | SKIP_GSCOOKIE_CHECK);
     }
     else
     {
index d324e41..345a670 100644 (file)
@@ -1231,7 +1231,7 @@ BOOL StackFrameIterator::Init(Thread *    pThread,
     }
     INDEBUG(m_pRealStartFrame = m_crawl.pFrame);
 
-    if (m_crawl.pFrame != FRAME_TOP)
+    if (m_crawl.pFrame != FRAME_TOP && !(m_flags & SKIP_GSCOOKIE_CHECK))
     {
         m_crawl.SetCurGSCookie(Frame::SafeGetGSCookiePtr(m_crawl.pFrame));
     }
@@ -1324,7 +1324,7 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp,
         _ASSERTE(m_crawl.pFrame != NULL);
     }
 
-    if (m_crawl.pFrame != FRAME_TOP)
+    if (m_crawl.pFrame != FRAME_TOP && !(m_flags & SKIP_GSCOOKIE_CHECK))
     {
         m_crawl.SetCurGSCookie(Frame::SafeGetGSCookiePtr(m_crawl.pFrame));
     }
@@ -3151,7 +3151,7 @@ void StackFrameIterator::PreProcessingForManagedFrames(void)
                                                         &m_crawl.codeManState);
 #endif // !DACCESS_COMPILE
 
-    if (m_pCachedGSCookie)
+    if (!(m_flags & SKIP_GSCOOKIE_CHECK) && m_pCachedGSCookie)
     {
         m_crawl.SetCurGSCookie(m_pCachedGSCookie);
     }
index ed16ac7..e4b6487 100644 (file)
@@ -3360,6 +3360,14 @@ public:
     // Refer to StackFrameIterator::Filter for detailed comments on this flag.
     #define GC_FUNCLET_REFERENCE_REPORTING 0x8000
 
+    // Stackwalking normally checks GS cookies on the fly, but there are cases in which the JIT reports
+    // incorrect epilog information. This causes the debugger to request stack walks in the epilog, checking
+    // an now invalid cookie. This flag allows the debugger stack walks to disable GS cookie checking.
+    
+    // This is a workaround for the debugger stackwalking. In general, the stackwalker and CrawlFrame
+    // may still execute GS cookie tracking/checking code paths.
+    #define SKIP_GSCOOKIE_CHECK 0x10000
+
     StackWalkAction StackWalkFramesEx(
                         PREGDISPLAY pRD,        // virtual register set at crawl start
                         PSTACKWALKFRAMESCALLBACK pCallback,