You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- When CRC runs out of process, instead of reading the current thread context of the crashed thread, read and use the crash context that was reported during the crash (which is different). - Added an optional context parameter to FGenericPlatformStackWalk::CaptureThreadStackBackTrace(), implemented it across all platforms, but only used on Windows. On Windows, fixed InitStackWalking() and InitStackWalkingForProcess() to reset the process that needs to be walked. - CRC, running out of process may run its own process or the Editor process and which ever was walking first ruled out the other. #jira UE-105006 - [CrashReporter] VCRUNTIME140!7fffce010000 + e390 #rb Johan.Berg #preflight 15217159 [CL 15319737 by Patrick Laflamme in ue5-main branch]
154 lines
5.6 KiB
C++
154 lines
5.6 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CrashReportClientApp.h"
|
|
#include "Windows/WindowsHWrapper.h"
|
|
#include "CrashReportClientDefines.h"
|
|
|
|
#if CRASH_REPORT_WITH_MTBF
|
|
#include "EditorAnalyticsSession.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "HAL/PlatformProcess.h"
|
|
#include "HAL/PlatformAtomics.h"
|
|
#include "HAL/PlatformStackWalk.h"
|
|
#include "Serialization/Archive.h"
|
|
#include "DiagnosticLogger.h"
|
|
#endif
|
|
|
|
#if CRASH_REPORT_WITH_MTBF && !PLATFORM_SEH_EXCEPTIONS_DISABLED
|
|
|
|
static ANSICHAR CrashStackTrace[8*1024] = {0};
|
|
|
|
void SaveCrcCrashException(EXCEPTION_POINTERS* ExceptionInfo)
|
|
{
|
|
// Try to write the exception code in the appropriate field if the session was created. The first crashing thread
|
|
// incrementing the counter wins the race and can write its exception code.
|
|
static volatile int32 CrashCount = 0;
|
|
if (FPlatformAtomics::InterlockedIncrement(&CrashCount) == 1)
|
|
{
|
|
TCHAR CrashEventLog[64];
|
|
FCString::Sprintf(CrashEventLog, TEXT("CRC/Crash:%d"), ExceptionInfo->ExceptionRecord->ExceptionCode);
|
|
FDiagnosticLogger::Get().LogEvent(CrashEventLog);
|
|
|
|
uint64 MonitoredEditorPid;
|
|
if (FParse::Value(GetCommandLineW(), TEXT("-MONITOR="), MonitoredEditorPid))
|
|
{
|
|
FTimespan Timeout = FTimespan::FromSeconds(2);
|
|
if (FEditorAnalyticsSession::Lock(Timeout)) // This lock is reentrant for the same process.
|
|
{
|
|
FEditorAnalyticsSession MonitoredSession;
|
|
if (FEditorAnalyticsSession::FindSession(MonitoredEditorPid, MonitoredSession))
|
|
{
|
|
if (!MonitoredSession.SaveMonitorExceptCode(ExceptionInfo->ExceptionRecord->ExceptionCode))
|
|
{
|
|
FDiagnosticLogger::Get().LogEvent("CRC/ExceptCodeNotSaved");
|
|
}
|
|
}
|
|
FEditorAnalyticsSession::Unlock();
|
|
}
|
|
}
|
|
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_HEAP_CORRUPTION)
|
|
{
|
|
// Try to get the exception callstack to log to figure out why CRC crashed. This is not robust because this runs
|
|
// in the crashing processs and it allocates memory/use callstack, but we may still be able to get some useful data.
|
|
if (FPlatformStackWalk::InitStackWalkingForProcess(FProcHandle()))
|
|
{
|
|
FPlatformStackWalk::StackWalkAndDump(CrashStackTrace, UE_ARRAY_COUNT(CrashStackTrace), 0);
|
|
if (CrashStackTrace[0] != 0)
|
|
{
|
|
FDiagnosticLogger::Get().LogEvent(ANSI_TO_TCHAR(CrashStackTrace));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Vectored Exception Handler (VEH) is added to capture heap corruption exceptions because those are not reaching the
|
|
* UnhandledExceptionFilter(). VEH has first and only chance to heap corrutpion exceptions before they got 'handled' by the OS.
|
|
*/
|
|
LONG WINAPI CrashReportVectoredExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo)
|
|
{
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_HEAP_CORRUPTION)
|
|
{
|
|
SaveCrcCrashException(ExceptionInfo);
|
|
}
|
|
|
|
// Let the OS deal with the exception. (the process will crash)
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
/**
|
|
* Invoked when an exception was not handled by vectored exception handler(s) nor structured exception handler(s)(__try/__except).
|
|
* For good understanding a SEH inner working,take a look at EngineUnhandledExceptionFilter documentation in WindowsPlatformCrashContext.cpp.
|
|
*/
|
|
LONG WINAPI CrashReportUnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo)
|
|
{
|
|
SaveCrcCrashException(ExceptionInfo);
|
|
|
|
// Let the OS deal with the exception. (the process will crash)
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* WinMain, called when the application is started
|
|
*/
|
|
int WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR, _In_ int nCmdShow)
|
|
{
|
|
hInstance = hInInstance;
|
|
|
|
#if CRASH_REPORT_WITH_MTBF // For the Editor only.
|
|
FString Arguments(::GetCommandLineW());
|
|
if (Arguments.Contains(TEXT("-MONITOR=")) && !Arguments.Contains(TEXT("-RespawnedInstance")))
|
|
{
|
|
uint64 ChildPipe = 0;
|
|
FParse::Value(GetCommandLineW(), TEXT("-READ="), ChildPipe);
|
|
|
|
// Parse the process ID of the Editor that spawned this CRC.
|
|
uint32 MonitoredEditorPid = 0;
|
|
if (FParse::Value(GetCommandLineW(), TEXT("-MONITOR="), MonitoredEditorPid))
|
|
{
|
|
TCHAR RespawnExePathname[MAX_PATH];
|
|
GetModuleFileName(NULL, RespawnExePathname, MAX_PATH);
|
|
FString RespawnExeArguments(Arguments);
|
|
RespawnExeArguments.Append(" -RespawnedInstance");
|
|
uint32 RespawnPid = 0;
|
|
|
|
// Respawn itself to sever the process grouping with the Editor. If the user kills the Editor process group in task manager,
|
|
// CRC will not die at the same time, will be able to capture the Editor exit code and send the MTBF report to correctly
|
|
// identify the Editor 'AbnormalShutdown' as 'Killed' instead.
|
|
FProcHandle Handle = FPlatformProcess::CreateProc(
|
|
RespawnExePathname,
|
|
*RespawnExeArguments,
|
|
true, false, false,
|
|
&RespawnPid, 0,
|
|
nullptr,
|
|
reinterpret_cast<void*>(ChildPipe), // Ensure the child process inherit this pipe handle that was previously inherited from its parent.
|
|
nullptr);
|
|
|
|
if (Handle.IsValid())
|
|
{
|
|
FString PidPathname = FString::Printf(TEXT("%sue4-crc-pid-%d"), FPlatformProcess::UserTempDir(), MonitoredEditorPid);
|
|
if (TUniquePtr<FArchive> Ar = TUniquePtr<FArchive>(IFileManager::Get().CreateFileWriter(*PidPathname, FILEWRITE_EvenIfReadOnly)))
|
|
{
|
|
*Ar << RespawnPid;
|
|
}
|
|
|
|
FPlatformProcess::CloseProc(Handle);
|
|
}
|
|
}
|
|
RequestEngineExit(TEXT("Respawn instance."));
|
|
return 0; // Exit this intermediate instance, the Editor is waiting for it to continue.
|
|
}
|
|
|
|
#if !PLATFORM_SEH_EXCEPTIONS_DISABLED
|
|
::SetUnhandledExceptionFilter(CrashReportUnhandledExceptionFilter);
|
|
::AddVectoredExceptionHandler(0, CrashReportVectoredExceptionFilter);
|
|
#endif // !PLATFORM_SEH_EXCEPTIONS_DISABLED
|
|
#endif // CRASH_REPORT_WITH_MTBF
|
|
|
|
RunCrashReportClient(GetCommandLineW());
|
|
return 0;
|
|
}
|