A game-agnostic UE4.27 crash-context mod for UE4SS. It turns a bare crash line
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x000000000000004c
into a report naming what the Blueprint VM was doing when it died:
=== CrashContext report (UE4.27) ===
Crash class: Hardware exception
Exception: EXCEPTION_ACCESS_VIOLATION (0xC0000005) at 0x7FF6A1B2C3D4
Access violation reading address 0x000000000000004C
Faulting module: YourGame-Win64-Shipping.exe + 0x1B2C3D4 (module base 0x7FF6A0000000)
RIP=0x7FF6A1B2C3D4 RSP=... RBP=...
Crashing thread: 12345 (game thread)
Blueprint script stack (3 frame(s), innermost first):
[0] Function /Game/objects/foo.foo_C:UpdateTarget
self: foo_C /Game/maps/level.level:PersistentLevel.foo_37
UFunction*=0x... UObject*=0x...
bytecode offset: 0x1A4 of 0x820
MostRecentProperty: ObjectProperty /Game/objects/foo.foo_C:Target
CurrentNativeFunction: Function /Script/Engine.KismetSystemLibrary:K2_SetActorLocation
[1] Function /Game/objects/foo.foo_C:Tick
It uses only UE 4.27 engine internals and UE4SS reflection, so it works on any UE4.27 UE4SS title. Shipped via the VotV Thunderstore, not VotV-specific.
The engine's own script stack (FBlueprintContextTracker::ScriptStack) is compiled out in Shipping
(#if DO_BLUEPRINT_GUARD), so we can't read it. But the FFrame interpreter frames still live on the
game thread's stack, and FFrame::MostRecentProperty is set regardless of build config.
-
Own shadow stack (
ShadowStack.hpp). HooksProcessLocalScriptFunction(andProcessInternal) via UE4SS. In 4.27 every interpreter frame runs throughProcessLocalScriptFunctiononce, so a push there snapshots the liveFFrame*plus the stableUFunction*/UObject*. -
First-priority VEH (
CrashHandler.cpp). A vectored handler runs before any frame-based SEH filter (before UE's__except(ReportCrash)and UE4SS's minidump handler), reads the crashing thread's shadow stack, then returnsEXCEPTION_CONTINUE_SEARCHso the normal minidump still runs. Additive, not intercepting.
Every field is read inside a nested __try/__except with a hex fallback, so a secondary fault can't crash
the crash handler.
CrashContext_<timestamp>.login UE4SS's working directory (full copy, written first).- Appended to
UE4SS.login the same directory. - A modal dialog ("CrashContext (UE4.27)") with the crash class, exception, and top Blueprint frame.
The engine's own crash message and minidump are left untouched.
-
Hardware exceptions (
EXCEPTION_ACCESS_VIOLATIONetc.). The VEH sees them directly. -
Assertions / Fatal errors (
check/checkf/verify,UE_LOG(..., Fatal, ...),LowLevelFatalError). These don't fault; they go throughGError->Serialize -> ReportAssert, which callsRaiseException(0x4000, ...)with aFAssertInfo*inExceptionInformation[0]. The VEH handles0x4000(assert) and0x8000(GPU crash), reads the message out ofFAssertInfo, and dumps the same BP stack. No AOB, no symbols; the codes are fixed UE 4.27 constants.ReportAssertonly raises whenGIsGuarded, which holds during normal gameplay. A Fatal fired while unguarded (very early startup / late shutdown) exits without raising and is missed.ensure()(0xBDB70) is recoverable and ignored.
Cooked builds strip the offset-to-node map. The report gives UFunction + bytecode offset + property;
resolve it by opening the function in an editor copy that still has the map, or by disassembling the
bytecode.
Faulting module: <exe> + 0xRVA is all you get natively. Most shipped UE4 games are monolithic, so Epic's
engine PDBs won't symbolize the exe. Map the RVA with your own AOB anchors. The Blueprint story above needs
no symbols.
Built in-tree with the other cppmods (registered in cppmods/CMakeLists.txt). The DLL is copied to
MOD_OUTPUT_PATH_CRASHCONTEXTCPP; retarget that to your UE4SS Mods / shimloader mod directory. Reports
land in UE4SS's working directory next to UE4SS.log.
- UE4SS settings (default on):
[Hooks] HookProcessLocalScriptFunction = 1(and/orHookProcessInternal = 1). If both are0the shadow stack stays empty and reports are native-only. - Name resolution calls
GetFullName(), which allocates and reads the FName pool. Safe for a typical null-deref; if memory is corrupt it faults and falls back to raw pointers. It can theoretically deadlock if another thread holds an FName lock at crash time, rare for game-thread null derefs. - Stack overflow (
0xC00000FD): little stack left, so the report may be truncated or skipped. - First-chance: only hard fatal codes (AV, illegal instruction, div-by-zero, asserts) are acted on;
C++ EH (
0xE06D7363), ensures, and debug events are ignored. Capped at 24 reports/session. - Shadow-stack callbacks are
noexceptand allocation-free: a throwing script-hook callback tears down UE4SS's shared dispatcher and kills every mod's BP hooks.
| File | Role |
|---|---|
include/CrashContext/ShadowStack.hpp |
Per-thread shadow of the live BP VM stack; noexcept push/pop |
include/CrashContext/CrashHandler.hpp |
Install / remove API |
src/CrashHandler.cpp |
VEH + report writer (file + UE4SS.log + dialog) |
src/dllmain.cpp |
Mod entry; registers VM hooks and arms the handler |