UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
WindowsPlatformCrashContext.cpp File Reference
#include "Windows/WindowsPlatformCrashContext.h"
#include "BuildSettings.h"
#include "CoreGlobals.h"
#include "HAL/ExceptionHandling.h"
#include "HAL/FileManager.h"
#include "HAL/IConsoleManager.h"
#include "HAL/PlatformMallocCrash.h"
#include "HAL/PlatformOutputDevices.h"
#include "HAL/PlatformProcess.h"
#include "HAL/PlatformTime.h"
#include "HAL/PlatformTLS.h"
#include "HAL/ThreadHeartBeat.h"
#include "HAL/ThreadManager.h"
#include "Internationalization/Internationalization.h"
#include "Misc/App.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/CoreDelegates.h"
#include "Misc/EngineBuildSettings.h"
#include "Misc/EngineVersion.h"
#include "Misc/FeedbackContext.h"
#include "Misc/FileHelper.h"
#include "Misc/MessageDialog.h"
#include "Misc/OutputDeviceArchiveWrapper.h"
#include "Misc/OutputDeviceFile.h"
#include "Misc/OutputDeviceRedirector.h"
#include "Misc/Paths.h"
#include "Serialization/Archive.h"
#include "Templates/UniquePtr.h"
#include "Templates/UnrealTemplate.h"
#include "Windows/WindowsPlatformMisc.h"
#include "Windows/WindowsPlatformProcess.h"
#include "Windows/WindowsPlatformStackWalk.h"
#include <atomic>
#include <signal.h>
#include "Windows/AllowWindowsPlatformTypes.h"
#include <strsafe.h>
#include <dbghelp.h>
#include <Shlwapi.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <shellapi.h>
#include "Windows/HideWindowsPlatformTypes.h"
#include <ErrorRep.h>
#include <DbgHelp.h>

Classes

struct  FAssertInfo
 
class  FCrashReportingThread
 

Namespaces

namespace  UE
 
namespace  UE::Core
 
namespace  UE::Core::Private
 implementation
 

Macros

#define UE_LOG_CRASH_CALLSTACK   1
 
#define USE_CRASH_REPORTER_MONITOR   WITH_EDITOR
 
#define NOINITCRASHREPORTER   0
 
#define DISABLE_CRC_SUBMIT_AND_RESTART_BUTTON   0
 
#define HANDLE_ABORT_SIGNALS   1
 
#define WINDOWS_USE_WER   0
 
#define CR_CLIENT_MAX_PATH_LEN   265
 
#define CR_CLIENT_MAX_ARGS_LEN   256
 
#define DISABLE_DEBUG_INFO_DUE_TO_ASAN   0
 
#define HANDLE_CASE(x)   case x: ErrorString += TEXT(#x); break;
 

Enumerations

enum  EConstants { UE4_MINIDUMP_CRASHCONTEXT = LastReservedStream + 1 }
 

Functions

LONG WINAPI EngineUnhandledExceptionFilter (LPEXCEPTION_POINTERS ExceptionInfo)
 
LONG WINAPI UnhandledStaticInitException (LPEXCEPTION_POINTERS ExceptionInfo)
 
THIRD_PARTY_INCLUDES_START THIRD_PARTY_INCLUDES_END void CreateExceptionInfoString (EXCEPTION_RECORD *ExceptionRecord, TCHAR *OutErrorString, int32 ErrorStringBufSize)
 
int32 ReportCrash (LPEXCEPTION_POINTERS ExceptionInfo)
 
int32 ReportContinuableEventUsingCrashReportClient (ECrashContextType InType, EXCEPTION_POINTERS *ExceptionInfo, HANDLE InThreadHandle, uint32 InThreadId, void *ProgramCounter, const TCHAR *ErrorMessage, EErrorReportUI ReportUI)
 
void ReportAssert (const TCHAR *ErrorMessage, void *ProgramCounter)
 
FORCENOINLINE void ReportGPUCrash (const TCHAR *ErrorMessage, void *ProgramCounter)
 
void ReportHang (const TCHAR *ErrorMessage, const uint64 *StackFrames, int32 NumStackFrames, uint32 HungThreadId)
 
void ReportEnsure (const TCHAR *ErrorMessage, void *ProgramCounter)
 
FORCENOINLINE void ReportStall (const TCHAR *ErrorMessage, uint32 HitchThreadId)
 

Variables

const uint32 EnsureExceptionCode = ECrashExitCodes::UnhandledEnsure
 
const uint32 AssertExceptionCode = 0x4000
 
const uint32 GPUCrashExceptionCode = 0x8000
 
const uint32 OutOfMemoryExceptionCode = 0xc000
 
constexpr double DefaultCrashHandlingTimeoutSecs = 60.0
 
TArray< FString > OptionalAttachmentFilepaths
 
TOptional< FCrashReportingThreadGCrashReportingThread (InPlace)
 

Macro Definition Documentation

◆ CR_CLIENT_MAX_ARGS_LEN

#define CR_CLIENT_MAX_ARGS_LEN   256

◆ CR_CLIENT_MAX_PATH_LEN

#define CR_CLIENT_MAX_PATH_LEN   265

◆ DISABLE_CRC_SUBMIT_AND_RESTART_BUTTON

#define DISABLE_CRC_SUBMIT_AND_RESTART_BUTTON   0

◆ DISABLE_DEBUG_INFO_DUE_TO_ASAN

#define DISABLE_DEBUG_INFO_DUE_TO_ASAN   0

◆ HANDLE_ABORT_SIGNALS

#define HANDLE_ABORT_SIGNALS   1

◆ HANDLE_CASE

#define HANDLE_CASE (   x)    case x: ErrorString += TEXT(#x); break;

◆ NOINITCRASHREPORTER

#define NOINITCRASHREPORTER   0

◆ UE_LOG_CRASH_CALLSTACK

#define UE_LOG_CRASH_CALLSTACK   1

◆ USE_CRASH_REPORTER_MONITOR

#define USE_CRASH_REPORTER_MONITOR   WITH_EDITOR

◆ WINDOWS_USE_WER

#define WINDOWS_USE_WER   0

Enumeration Type Documentation

◆ EConstants

Platform specific constants.

Enumerator
UE4_MINIDUMP_CRASHCONTEXT 

Function Documentation

◆ CreateExceptionInfoString()

THIRD_PARTY_INCLUDES_START THIRD_PARTY_INCLUDES_END void CreateExceptionInfoString ( EXCEPTION_RECORD ExceptionRecord,
TCHAR OutErrorString,
int32  ErrorStringBufSize 
)

Creates an info string describing the given exception record. See MSDN docs on EXCEPTION_RECORD.

◆ EngineUnhandledExceptionFilter()

LONG WINAPI EngineUnhandledExceptionFilter ( LPEXCEPTION_POINTERS  ExceptionInfo)

Fallback for handling exceptions that aren't handled elsewhere.

The SEH mechanism is not very well documented, so to start with, few facts to know:

  • SEH uses 'handlers' and 'filters'. They have different roles and are invoked at different state.
  • Any unhandled exception is going to terminate the program whether it is a benign exception or a fatal one.
  • Vectored exception handlers, Vectored continue handlers and the unhandled exception filter are global to the process.
  • Exceptions occurring in a thread doesn't automatically halt other threads. Exception handling executes in thread where the exception fired. The other threads continue to run.
  • Several threads can crash concurrently.
  • Not all exceptions are equal. Some exceptions can be handled doing nothing more than catching them and telling the code to continue (like some user defined exception), some needs to be handled in a __except() clause to allow the program to continue (like access violation) and others are fatal and can only be reported but not continued (like stack overflow).
  • Not all machines are equal. Different exceptions may be fired on different machines for the same usage of the program. This seems especially true when using the OS 'open file' dialog where the user specific extensions to the Windows Explorer get loaded in the process.
  • If an exception handler/filter triggers another exception, the new inner exception is handled recursively. If the code is not robust, it may retrigger that inner exception over and over. This eventually stops with a stack overflow, at which point the OS terminates the program and the original exception is lost.

Usually, when an exception occurs, Windows executes following steps (see below for unusual cases): 1- Invoke the vectored exception handlers registered with AddVectoredExceptionHandler(), if any.

  • In general, this is too soon to handle an exception because local structured exception handlers did not execute yet and many exceptions are handled there.
  • If a registered vectored exception handler returns EXCEPTION_CONTINUE_EXECUTION, the vectored continue handler(s), are invoked next (see number 4 below)
  • If a registered vectored exception handler returns EXCEPTION_CONTINUE_SEARCH, the OS skip this one and continue iterating the list of vectored exception handlers.
  • If a registered vectored exception handler returns EXCEPTION_EXECUTE_HANDLER, in my tests, this was equivalent to returning EXCEPTION_CONTINUE_SEARCH.
  • If no vectored exception handlers are registered or all registered one return EXCEPTION_CONTINUE_SEARCH, the structured exception handlers (__try/__except) are executed next.
  • At this stage, be careful when returning EXCEPTION_CONTINUE_EXECUTION. For example, continuing after an access violation would retrigger the exception immediatedly. 2- If the exception wasn't handled by a vectored exception handler, invoke the structured exception handlers (the __try/__except clauses)
  • That let the code manage exceptions more locally, for the Engine, we want that to run first.
  • When the filter expression in __except(filterExpression) { block } clause returns EXCEPTION_EXECUTE_HANDLER, the 'block' is executed, the code continue after the block. The exception is considered handled.
  • When the filter expression in __except(filterExpression) { block } clause returns EXCEPTION_CONTINUE_EXECUTION, the 'block' is not executed and vectored continue exceptions handlers (if any) gets called. (see number 4 below)
  • When the filter expression in __except(filterExpression) { block } clause returns EXCEPTION_CONTINUE_SEARCH, the 'block' is not executed and the search continue for the next __try/__except in the callstack.
  • If all unhandled exception filters within the call stack were executed and all of them returned returned EXCEPTION_CONTINUE_SEARCH, the unhandled exception filter is invoked. (see number 3 below)
  • The __except { block } allows the code to continue from most exceptions, even from an access violation because code resume after the except block, not at the point of the exception. 3- If the exception wasn't handled yet, the system calls the function registered with SetUnhandedExceptionFilter(). There is only one such function, the last to register override the previous one.
  • At that point, both vectored exception handlers and structured exception handlers have had a chance to handle the exception but did not.
  • If this function returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_EXECUTE_HANDLER, by default, the OS handler is invoked and the program is terminated.
  • If this function returns EXCEPTION_CONTINUE_EXECUTION, the vectored continue handlers are invoked (see number 4 below) 4- If a handler or a filter returned the EXCEPTION_CONTINUE_EXECUTION, the registered vectored continue handlers are invoked.
  • This is last chance to do something about an exception. The program was allowed to continue by a previous filter/handler, effectively ignoring the exception.
  • The handler can return EXCEPTION_CONTINUE_SEARCH to observe only. The OS will continue and invoke the next handler in the list.
  • The handler can short cut other continue handlers by returning EXCEPTION_CONTINUE_EXECUTION which resume the code immediatedly.
  • In my tests, if a vectored continue handler returns EXCEPTION_EXECUTE_HANDLER, this is equivalent to returning EXCEPTION_CONTINUE_SEARCH.
  • By default, if no handlers are registered or all registered handler(s) returned EXCEPTION_CONTINUE_SEARCH, the program resumes execution at the point of the exception.

Inside a Windows OS callback, in a 64-bit application, a different flow than the one described is used.

Other SEH particularities:

  • A stack buffer overflow bypasses SEH entirely and the application exits with code: -1073740791 (STATUS_STACK_BUFFER_OVERRUN).
  • A stack overflow exception occurs when not enough space remains to push what needs to be pushed, but it doesn't means it has no stack space left at all. The exception will be reported if enough stack space is available to call/run SEH, otherwise, the app exits with code: -1073741571 (STATUS_STACK_OVERFLOW)
  • Fast fail exceptions bypasse SEH entirely and the application exits with code: -1073740286 (STATUS_FAIL_FAST_EXCEPTION) or 1653 (ERROR_FAIL_FAST_EXCEPTION)
  • Heap corruption (like a double free) is a special exception. It is likely only visible to Vectored Exception Handler (VEH) before possibly beeing handled by Windows Error Reporting (WER). A popup may be shown asking to debug or exit. The application may exit with code -1073740940 (STATUS_HEAP_CORRUPTION) or 255 (Abort) depending on the situation.

The engine hooks itself in the unhandled exception filter. This is the best place to be as it runs after structured exception handlers and it can be easily overriden externally (because there can only be one) to do something else.

◆ ReportAssert()

void ReportAssert ( const TCHAR ErrorMessage,
void ProgramCounter 
)

This is the last place to gather memory stats before exception.

◆ ReportContinuableEventUsingCrashReportClient()

int32 ReportContinuableEventUsingCrashReportClient ( ECrashContextType  InType,
EXCEPTION_POINTERS ExceptionInfo,
HANDLE  InThreadHandle,
uint32  InThreadId,
void ProgramCounter,
const TCHAR ErrorMessage,
EErrorReportUI  ReportUI 
)

A wrapper for ReportCrashUsingCrashReportClient that creates a new ensure crash context

◆ ReportCrash()

int32 ReportCrash ( LPEXCEPTION_POINTERS  ExceptionInfo)

◆ ReportEnsure()

void ReportEnsure ( const TCHAR ErrorMessage,
void ProgramCounter 
)

Report an ensure to the crash reporting system

◆ ReportGPUCrash()

FORCENOINLINE void ReportGPUCrash ( const TCHAR ErrorMessage,
void ProgramCounter 
)

This is the last place to gather memory stats before exception.

◆ ReportHang()

void ReportHang ( const TCHAR ErrorMessage,
const uint64 StackFrames,
int32  NumStackFrames,
uint32  HungThreadId 
)

◆ ReportStall()

FORCENOINLINE void ReportStall ( const TCHAR ErrorMessage,
uint32  HitchThreadId 
)

Report a hitch to the crash reporting system

◆ UnhandledStaticInitException()

LONG WINAPI UnhandledStaticInitException ( LPEXCEPTION_POINTERS  ExceptionInfo)

Variable Documentation

◆ AssertExceptionCode

const uint32 AssertExceptionCode = 0x4000

◆ DefaultCrashHandlingTimeoutSecs

constexpr double DefaultCrashHandlingTimeoutSecs = 60.0
constexpr

◆ EnsureExceptionCode

const uint32 EnsureExceptionCode = ECrashExitCodes::UnhandledEnsure

Code for an assert exception

◆ GCrashReportingThread

TOptional< FCrashReportingThread > GCrashReportingThread(InPlace) ( InPlace  )

◆ GPUCrashExceptionCode

const uint32 GPUCrashExceptionCode = 0x8000

◆ OptionalAttachmentFilepaths

TArray<FString> OptionalAttachmentFilepaths

Optional attachments

◆ OutOfMemoryExceptionCode

const uint32 OutOfMemoryExceptionCode = 0xc000