diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp index 57a4aa12dfea..a28adace88ab 100644 --- a/src/classlibnative/bcltype/system.cpp +++ b/src/classlibnative/bcltype/system.cpp @@ -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) { diff --git a/src/vm/crossgencompile.cpp b/src/vm/crossgencompile.cpp index 790b0d817c66..f6a1338c84cf 100644 --- a/src/vm/crossgencompile.cpp +++ b/src/vm/crossgencompile.cpp @@ -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); diff --git a/src/vm/eepolicy.cpp b/src/vm/eepolicy.cpp index bdfe0fbf671e..e15af92bfce5 100644 --- a/src/vm/eepolicy.cpp +++ b/src/vm/eepolicy.cpp @@ -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; diff --git a/src/vm/eepolicy.h b/src/vm/eepolicy.h index c41d16bc09f6..44e0073754f0 100644 --- a/src/vm/eepolicy.h +++ b/src/vm/eepolicy.h @@ -124,7 +124,7 @@ class EEPolicy 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 @@ class EEPolicy 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 diff --git a/src/vm/eventreporter.cpp b/src/vm/eventreporter.cpp index c73af36b5539..74362802dcde 100644 --- a/src/vm/eventreporter.cpp +++ b/src/vm/eventreporter.cpp @@ -343,6 +343,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. @@ -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. } diff --git a/src/vm/eventreporter.h b/src/vm/eventreporter.h index 54317133ddf7..abd35befc48f 100644 --- a/src/vm/eventreporter.h +++ b/src/vm/eventreporter.h @@ -61,6 +61,8 @@ class EventReporter 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 @@ class EventReporter 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_ diff --git a/src/vm/excep.cpp b/src/vm/excep.cpp index 09283f78391f..3ba3d05a82f2 100644 --- a/src/vm/excep.cpp +++ b/src/vm/excep.cpp @@ -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 diff --git a/src/vm/excep.h b/src/vm/excep.h index 4261c3cff3c3..6df9a98452ab 100644 --- a/src/vm/excep.h +++ b/src/vm/excep.h @@ -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);