Failfast windows event log (#16875)
authorSung Yoon Whang <suwhang@microsoft.com>
Tue, 27 Mar 2018 21:42:12 +0000 (14:42 -0700)
committerGitHub <noreply@github.com>
Tue, 27 Mar 2018 21:42:12 +0000 (14:42 -0700)
* Add FailFast error log to Windows Event Log

* change const wchar * to lpcwstr

* Enable sending unhandled exception info to Windows Event Log

* Change log format to match console output and address PR comments

* Remove more comments

* Change the order DoReportForUnhandledException to do a safety check first before calling managed code

* Fix parameter name in header file

* Add Windows Event logging in DefaultCatchHandler and remove DoReportForUnhandledException

* Add back event reporting for ignored unhandled exception cases, fix broken UNIX builds

* Fix more broken unix builds

* Fix typo

* Address PR comments

src/classlibnative/bcltype/system.cpp
src/vm/crossgencompile.cpp
src/vm/eepolicy.cpp
src/vm/eepolicy.h
src/vm/eventreporter.cpp
src/vm/eventreporter.h
src/vm/excep.cpp
src/vm/excep.h

index 57a4aa1..a28adac 100644 (file)
@@ -460,7 +460,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
         WszOutputDebugString(W("\"\r\n"));
     }
 
-    const WCHAR * argExceptionString = NULL;
+    LPCWSTR argExceptionString = NULL;
     StackSString msg;
     if (gc.refExceptionForWatsonBucketing != NULL)
     {
index cea93bf..f608afc 100644 (file)
@@ -384,7 +384,7 @@ extern "C" UINT_PTR STDCALL GetCurrentIP()
     return 0;
 }
 
-void EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, const WCHAR * argExceptionString)
+void EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
 { 
     fprintf(stderr, "Fatal error: %08x\n", exitCode);
     ExitProcess(exitCode);
index bdfe0fb..e15af92 100644 (file)
@@ -1176,7 +1176,7 @@ inline void LogCallstackForLogWorker()
 // Return Value:
 //    None
 //
-inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, const WCHAR * argExceptionString)
+inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
 {
     WRAPPER_NO_CONTRACT;
 
@@ -1205,7 +1205,7 @@ inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pE
                 PrintToStdErrA("\n");
                 PrintToStdErrA("Exception details:");
                 PrintToStdErrA("\n");
-                PrintToStdErrW(argExceptionString);
+                PrintToStdErrW((WCHAR*)argExceptionString);
                 PrintToStdErrA("\n");
             }
         }
@@ -1220,7 +1220,7 @@ inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pE
 // Log an error to the event log if possible, then throw up a dialog box.
 //
 
-void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, const WCHAR * argExceptionString)
+void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
 {
     STATIC_CONTRACT_NOTHROW;
     STATIC_CONTRACT_GC_TRIGGERS;
@@ -1262,7 +1262,7 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
             else if (exitCode == (UINT)COR_E_CODECONTRACTFAILED)
                 failureType = EventReporter::ERT_CodeContractFailed;
             EventReporter reporter(failureType);
-
+            StackSString s(argExceptionString);
 
             if ((exitCode == (UINT)COR_E_FAILFAST) || (exitCode == (UINT)COR_E_CODECONTRACTFAILED) || (exitCode == (UINT)CLR_E_GC_OOM))
             {
@@ -1271,6 +1271,11 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
                     reporter.AddDescription((WCHAR*)pszMessage);
                 }
 
+                if (argExceptionString)
+                {
+                    reporter.AddFailFastStackTrace(s);
+                }
+
                 if (exitCode != (UINT)CLR_E_GC_OOM)
                     LogCallstackForEventReporter(reporter);
             }
@@ -1486,7 +1491,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE
     UNREACHABLE();
 }
 
-void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage /* = NULL */, PEXCEPTION_POINTERS pExceptionInfo /* = NULL */, LPCWSTR errorSource /* = NULL */, const WCHAR * argExceptionString /* = NULL */)
+void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage /* = NULL */, PEXCEPTION_POINTERS pExceptionInfo /* = NULL */, LPCWSTR errorSource /* = NULL */, LPCWSTR argExceptionString /* = NULL */)
 {
     WRAPPER_NO_CONTRACT;
 
index c41d16b..44e0073 100644 (file)
@@ -124,7 +124,7 @@ public:
 
     static void HandleExitProcess(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete);
 
-    static void DECLSPEC_NORETURN HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage=NULL, PEXCEPTION_POINTERS pExceptionInfo= NULL, LPCWSTR errorSource=NULL, const WCHAR * argExceptionString=NULL);
+    static void DECLSPEC_NORETURN HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage=NULL, PEXCEPTION_POINTERS pExceptionInfo= NULL, LPCWSTR errorSource=NULL, LPCWSTR argExceptionString=NULL);
 
     static void DECLSPEC_NORETURN HandleFatalStackOverflow(EXCEPTION_POINTERS *pException, BOOL fSkipDebugger = FALSE);
 
@@ -147,7 +147,7 @@ private:
     BOOL IsValidActionForFailure(EClrFailure failure, EPolicyAction action);
     EPolicyAction GetFinalAction(EPolicyAction action, Thread *pThread);
 
-    static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, const WCHAR * argExceptionString=NULL);
+    static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString=NULL);
 
     // IMPORTANT NOTE: only the following two functions should be calling ExitProcessViaShim.
     // - CorHost2::ExitProcess
index c73af36..7436280 100644 (file)
@@ -345,6 +345,41 @@ void EventReporter::AddStackTrace(SString& s)
 
 //---------------------------------------------------------------------------------------
 //
+// Add the stack trace of exception passed to managed FailFast call (Environment.FailFast()) to Event Log
+//
+// Arguments:
+//    s       - String representation of the stack trace of argument exception
+//
+// Return Value:
+//    None.
+//
+void EventReporter::AddFailFastStackTrace(SString& s)
+{
+    CONTRACTL
+    {
+        THROWS;
+        GC_NOTRIGGER;
+        SO_INTOLERANT;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    _ASSERTE(m_eventType == ERT_ManagedFailFast);
+    InlineSString<80> ssMessage;
+    if (!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTION))
+    {
+        m_Description.Append(W("Exception stack:\n"));
+    }
+    else
+    {
+        m_Description.Append(ssMessage);
+    }
+    m_Description.Append(s);
+    m_Description.Append(W("\n"));
+}
+
+//---------------------------------------------------------------------------------------
+//
 // Generate an entry in EventLog.
 //
 // Arguments:
@@ -448,7 +483,6 @@ BOOL ShouldLogInEventLog()
     }
     CONTRACTL_END;
 
-#ifndef FEATURE_CORESYSTEM
     // If the process is being debugged, don't log
     if ((CORDebuggerAttached() || IsDebuggerPresent())
 #ifdef _DEBUG
@@ -471,10 +505,6 @@ BOOL ShouldLogInEventLog()
         return FALSE;
     else
         return TRUE;
-#else
-    // no event log on Apollo
-    return FALSE;
-#endif //!FEATURE_CORESYSTEM
 }
 
 //---------------------------------------------------------------------------------------
@@ -645,7 +675,7 @@ void ReportExceptionStackHelper(OBJECTREF exObj, EventReporter& reporter, SmallS
 
 //---------------------------------------------------------------------------------------
 //
-// Generate an EventLog entry for unhandled exception.
+// Generate an EventLog entry for unhandled exceptions that are not sent to DefaultCatchHandler.
 //
 // Arguments:
 //    pExceptionInfo - Exception information
@@ -653,10 +683,10 @@ void ReportExceptionStackHelper(OBJECTREF exObj, EventReporter& reporter, SmallS
 // Return Value:
 //    None
 //
-void DoReportForUnhandledException(PEXCEPTION_POINTERS pExceptionInfo)
+void DoReportForUnhandledNativeException(PEXCEPTION_POINTERS pExceptionInfo)
 {
     WRAPPER_NO_CONTRACT;
-    
+
     if (ShouldLogInEventLog())
     {
         Thread *pThread = GetThread();
@@ -664,107 +694,21 @@ void DoReportForUnhandledException(PEXCEPTION_POINTERS pExceptionInfo)
         EX_TRY
         {
             StackSString s;
-            if (pThread && pThread->HasException() != NULL)
-            {
-                GCX_COOP();
-                struct
-                {
-                    OBJECTREF throwable;
-                    STRINGREF originalExceptionMessage;
-                } gc;
-                ZeroMemory(&gc, sizeof(gc));
-                
-                GCPROTECT_BEGIN(gc);
-
-                gc.throwable = pThread->GetThrowable();
-                _ASSERTE(gc.throwable != NULL);
-
-                // On CoreCLR, managed code execution happens in non-default AppDomains and all threads have an AD transition
-                // at their base from DefaultDomain to the target Domain before they start executing managed code. Thus, when 
-                // an exception goes unhandled in a non-default AppDomain on a reverse pinvoke thread, the original exception details are copied 
-                // to the Message property of System.CrossAppDomainMarshaledException instance at the AD transition boundary,
-                // and the exception is then thrown in the calling AppDomain. This is done since CoreCLR does not support marshaling of 
-                // objects across AppDomains.
-                //
-                // On SL, exceptions dont go unhandled to the OS. But in WLC, they can. Thus, when the scenario above happens for WLC,
-                // the OS will invoke CoreCLR's registered UEF and reach here to write the stacktrace from the 
-                // exception object (which will be a CrossAppDomainMarshaledException instance) to the event log. At this point,
-                // we shall be in DefaultDomain. 
-                //
-                // However, the original exception details are in the Message property of CrossAppDomainMarshaledException. So, we should
-                // look that up and if it is not empty, add those details to the EventReporter so that they get written to the
-                // event log as well.
-                //
-                // We can also be here when in non-DefaultDomain an exception goes unhandled on a pure managed thread. In such a case,
-                // we wont have CrossAppDomainMarshaledException instance but the original exception object that will be used to extract
-                //  the stack trace from.
-                if (pThread->GetDomain()->IsDefaultDomain())
-                {
-                    if (IsExceptionOfType(kCrossAppDomainMarshaledException, &(gc.throwable)))
-                    {
-                        // This is a CrossAppDomainMarshaledException instance - check if it has
-                        // something for us in the Message property.
-                        gc.originalExceptionMessage = ((EXCEPTIONREF)gc.throwable)->GetMessage();
-                        if (gc.originalExceptionMessage != NULL)
-                        {
-                            // Ok - so, we have details about the original exception. Add them to the
-                            // EventReporter object so that they get written to the event log.
-                            reporter.AddDescription(gc.originalExceptionMessage->GetBuffer());
-
-                            LOG((LF_EH, LL_INFO100, "DoReportForUnhandledException - Added original exception details to EventReporter from CrossAppDomainMarshaledException object.\n"));
-                        }
-                        else
-                        {
-                            LOG((LF_EH, LL_INFO100, "DoReportForUnhandledException - Original exception details not present in CrossAppDomainMarshaledException object.\n"));
-                        }
-                    }
-                }
-                else
-                {
-                    if (IsException(gc.throwable->GetMethodTable()))
-                    {
-                        SmallStackSString wordAt;
-                        if (!wordAt.LoadResource(CCompRC::Optional, IDS_ER_WORDAT))
-                        {
-                            wordAt.Set(W("   at"));
-                        }
-                        else
-                        {
-                            wordAt.Insert(wordAt.Begin(), W("   "));
-                        }
-                        wordAt += W(" ");
-
-                        ReportExceptionStackHelper(gc.throwable, reporter, wordAt, /* recursionLimit = */10);
-                    }
-                    else
-                    {
-                        TypeString::AppendType(s, TypeHandle(gc.throwable->GetMethodTable()), TypeString::FormatNamespace | TypeString::FormatFullInst);
-                        reporter.AddDescription(s);
-                        reporter.BeginStackTrace();
-                        LogCallstackForEventReporterWorker(reporter);
-                    }
-                }
-
-                GCPROTECT_END();
-            }
-            else
-            {
-                InlineSString<80> ssErrorFormat;
-                if(!ssErrorFormat.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTIONINFO))
-                    ssErrorFormat.Set(W("exception code %1, exception address %2"));
-                SmallStackSString exceptionCodeString;
-                exceptionCodeString.Printf(W("%x"), pExceptionInfo->ExceptionRecord->ExceptionCode);
-                SmallStackSString addressString;
-                addressString.Printf(W("%p"), (UINT_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress);
-                s.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)ssErrorFormat, 0, 0, exceptionCodeString, addressString);
-                reporter.AddDescription(s);
-                if (pThread)
-                {
-                    LogCallstackForEventReporter(reporter);
-                }
-            }
+        InlineSString<80> ssErrorFormat;
+        if (!ssErrorFormat.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTIONINFO))
+            ssErrorFormat.Set(W("exception code %1, exception address %2"));
+        SmallStackSString exceptionCodeString;
+        exceptionCodeString.Printf(W("%x"), pExceptionInfo->ExceptionRecord->ExceptionCode);
+        SmallStackSString addressString;
+        addressString.Printf(W("%p"), (UINT_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress);
+        s.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)ssErrorFormat, 0, 0, exceptionCodeString, addressString);
+        reporter.AddDescription(s);
+        if (pThread)
+        {
+            LogCallstackForEventReporter(reporter);
+        }
         }
-        EX_CATCH
+            EX_CATCH
         {
             // We are reporting an exception.  If we throw while working on this, it is not fatal.
         }
index 5431713..abd35be 100644 (file)
@@ -61,6 +61,8 @@ public:
     void BeginStackTrace();
     // Add one frame to the callstack part
     void AddStackTrace(SString& s);
+    // Add failfast stack trace
+    void AddFailFastStackTrace(SString& s);
     // Report to the EventLog
     void Report();
 };
@@ -69,7 +71,8 @@ public:
 BOOL ShouldLogInEventLog();
 // Record managed callstack in EventReporter.
 void LogCallstackForEventReporter(EventReporter& reporter);
-// Generate a report in EventLog for unhandled exception for both managed and unmanaged.
-void DoReportForUnhandledException(PEXCEPTION_POINTERS pExceptionInfo);
-
+// Record unhandled native exceptions.
+void DoReportForUnhandledNativeException(PEXCEPTION_POINTERS pExceptionInfo);
+// Helper method for logging stack trace in EventReporter
+void ReportExceptionStackHelper(OBJECTREF exObj, EventReporter& reporter, SmallStackSString& wordAt, int recursionLimit);
 #endif // _eventreporter_h_
index 09283f7..3ba3d05 100644 (file)
@@ -28,6 +28,7 @@
 #include "shimload.h"
 #include "eeconfig.h"
 #include "virtualcallstub.h"
+#include "typestring.h"
 
 #ifndef FEATURE_PAL
 #include "dwreport.h"
@@ -5234,10 +5235,6 @@ LONG InternalUnhandledExceptionFilter_Worker(
 #endif // DEBUGGING_SUPPORTED
 
 
-#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
-        DoReportForUnhandledException(pParam->pExceptionInfo);
-#endif // FEATURE_EVENT_TRACE    
-
         //
         // Except for notifying debugger, ignore exception if unmanaged, or
         // if it's a debugger-generated exception or user breakpoint exception.
@@ -5245,6 +5242,9 @@ LONG InternalUnhandledExceptionFilter_Worker(
         if (tore.GetType() == TypeOfReportedError::NativeThreadUnhandledException)
         {
             pParam->retval = EXCEPTION_CONTINUE_SEARCH;
+#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
+            DoReportForUnhandledNativeException(pParam->pExceptionInfo);
+#endif
             goto lDone;
         }
 
@@ -5252,15 +5252,17 @@ LONG InternalUnhandledExceptionFilter_Worker(
         {
             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker, ignoring the exception\n"));
             pParam->retval = EXCEPTION_CONTINUE_SEARCH;
+#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
+            DoReportForUnhandledNativeException(pParam->pExceptionInfo);
+#endif
             goto lDone;
         }
 
         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Calling DefaultCatchHandler\n"));
 
-
         // Call our default catch handler to do the managed unhandled exception work.
         DefaultCatchHandler(pParam->pExceptionInfo, NULL, useLastThrownObject,
-            TRUE /*isTerminating*/, FALSE /*isThreadBaseFIlter*/, FALSE /*sendAppDomainEvents*/);
+            TRUE /*isTerminating*/, FALSE /*isThreadBaseFIlter*/, FALSE /*sendAppDomainEvents*/, TRUE /* sendWindowsEventLog */);
 
 lDone: ;
     }
@@ -5510,8 +5512,10 @@ void STDMETHODCALLTYPE
 DefaultCatchHandlerExceptionMessageWorker(Thread* pThread,
                                           OBJECTREF throwable,
                                           __inout_ecount(buf_size) WCHAR *buf,
-                                          const int buf_size)
+                                          const int buf_size,
+                                          BOOL sendWindowsEventLog)
 {
+    GCPROTECT_BEGIN(throwable);
     if (throwable != NULL)
     {
         PrintToStdErrA("\n");
@@ -5532,7 +5536,39 @@ DefaultCatchHandlerExceptionMessageWorker(Thread* pThread,
         }
 
         PrintToStdErrA("\n");
+
+#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
+        // Send the log to Windows Event Log
+        if (sendWindowsEventLog && ShouldLogInEventLog())
+        {
+            EX_TRY
+            {
+                EventReporter reporter(EventReporter::ERT_UnhandledException);
+
+                if (IsException(throwable->GetMethodTable()))
+                {
+                    if (!message.IsEmpty())
+                    {
+                        reporter.AddDescription(message);
+                    }
+                    reporter.Report();
+                }
+                else
+                {
+                    StackSString s;
+                    TypeString::AppendType(s, TypeHandle(throwable->GetMethodTable()), TypeString::FormatNamespace | TypeString::FormatFullInst);
+                    reporter.AddDescription(s);
+                    LogCallstackForEventReporter(reporter);
+                }
+            }
+            EX_CATCH
+            {
+            }
+            EX_END_CATCH(SwallowAllExceptions);
+        }
+#endif
     }
+    GCPROTECT_END();
 }
 
 //******************************************************************************
@@ -5544,7 +5580,8 @@ DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionPointers,
                     BOOL useLastThrownObject,
                     BOOL isTerminating,
                     BOOL isThreadBaseFilter,
-                    BOOL sendAppDomainEvents)
+                    BOOL sendAppDomainEvents,
+                    BOOL sendWindowsEventLog)
 {
     CONTRACTL
     {
@@ -5724,7 +5761,7 @@ DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionPointers,
                 {
                     // this is stack heavy because of the CQuickWSTRBase, so we break it out
                     // and don't have to carry the weight through our other code paths.
-                    DefaultCatchHandlerExceptionMessageWorker(pThread, throwable, buf, buf_size);
+                    DefaultCatchHandlerExceptionMessageWorker(pThread, throwable, buf, buf_size, sendWindowsEventLog);
                 }
             }
             EX_CATCH
index 4261c3c..6df9a98 100644 (file)
@@ -241,7 +241,8 @@ void STDMETHODCALLTYPE DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionInfo,
                                            BOOL useLastThrownObject = FALSE,
                                            BOOL isTerminating = FALSE,
                                            BOOL isThreadBaseFilter = FALSE,
-                                           BOOL sendAppDomainEvents = TRUE);
+                                           BOOL sendAppDomainEvents = TRUE,
+                                           BOOL sendWindowsEventLog = FALSE);
 
 void ReplaceExceptionContextRecord(T_CONTEXT *pTarget, T_CONTEXT *pSource);