Summary
SlateRHIRenderer::ScreenshotState holds three RAW pointers — FSlateViewportInfo*,
TArray, TArray — and is only cleared when the window it targets is actually rendered.
FSlateApplication::TakeScreenshot (SlateApplication.cpp:4443) stores &OutColorData, a pointer to its CALLER’s TArray, then calls PrivateDrawWindows and returns. It does not clear ScreenshotState on the path where the capture does not happen.
If the target window is not rendered that frame — an occluded or minimised editor presents no frame — then bScreenshotProcessed is never set, so the “ScreenshotState = {}” at SlateRHIRenderer.cpp:1754-1757 never runs. The state persists indefinitely while the caller’s TArray goes out of scope, leaving ScreenshotState.ColorData dangling.
On a later frame, a viewport whose address compares equal to the stale ViewportToCapture (the same viewport finally drawing, or a recycled allocation at the same address after a PIE teardown) matches at SlateRHIRenderer.cpp:1180, which adds a readback pass whose lambda captures the dead pointer. SlateRHIRenderer.cpp:1205 then calls RHICmdList.ReadSurfaceData(…, *ColorData, …), which writes through it inside D3D12RHI and crashes.
There is no clear on viewport destruction, no clear on window destruction, and no timeout. The only escape is a capture that actually succeeds.
Impact: an editor screenshot request that cannot be satisfied does not merely fail — it leaves the process armed. The crash lands 2.5-8.5 minutes later, on the render thread, with nothing in the log connecting it to the screenshot, which makes it very hard to attribute.
Reproduced twice on this machine. Both crashes are byte-identical at the instruction level: identical PCallStackHash, identical faulting offset (UnrealEditor-D3D12RHI +0x10CADC), and both faulting on a WRITE to user32.dll +0xBBEC — the same read-only .text address under two different ASLR bases.
Environment:
UE 5.8.1 (++UE5+Release-5.8-CL-56057345), Win64 Development Editor, D3D12
Windows 11 25H2 (10.0.26200.9168)
NVIDIA GeForce RTX 5080, driver 32.0.16.1047 (hybrid with Intel iGPU)
Intel Core Ultra 5 245K, 64 GB
What Type of Bug are you experiencing?
Editor
Steps to Reproduce
- Open any project in a Development editor build using the D3D12 RHI.
- Ensure a UMG/Slate window is being drawn (we used a campaign UI in PIE, but the screen content is not important).
- Make the editor window NOT PRESENT A FRAME — minimise it, or fully occlude it behind another window. (Our case: the editor ran in the background while driven over a scripting/automation connection.)
- Request a UI screenshot of that window, i.e. reach SlateApplication::TakeScreenshot. We issued the console command “Shot showui” against the game viewport; HighResShot with UI, or a direct TakeScreenshot call, exercises the same path.
- Observe the capture never completes: no file is written to Saved/Screenshots/, and no screenshot line appears in the log. TakeScreenshot returns false.
- Allow the caller’s TArray to go out of scope (it is a local in the calling frame).
- Start PIE and then stop it, so viewports are torn down and reallocated.
- Leave the editor idle.
Crash occurs on the render thread 2.5 - 8.5 minutes later with no further user action. In our two occurrences the gap was 2m 27s and 8m 36s after the unfulfilled request.
Expected Result
A screenshot request that cannot be satisfied is discarded safely. Either:
- ScreenshotState is cleared when the request cannot be serviced (TakeScreenshot returning false should not leave state behind), or
- it is cleared when the target FSlateViewportInfo / SWindow is destroyed, or
- it holds a weak/owning reference rather than a raw pointer to caller-owned memory.
In no case should a failed screenshot leave the renderer holding a pointer to freed memory, and the editor should not crash minutes later as a result.
Observed Result
The editor crashes on the render thread, minutes after the screenshot request, with:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION writing address 0x00007fffb366bbec IsRequestingExit: false
Breadcrumbs ‘RDGExecute_RenderThread’: SlateUI → RenderGraphExecute - Slate
Two occurrences, and they are the same bug to the instruction:
crash 1 crash 2
PCallStackHash C742AF05E027BF32E500E164C2A2A69D0CC3D7FD (identical)
faulting instruction UnrealEditor-D3D12RHI +0x10CADC (identical)
access WRITE WRITE
faulted-on address 0x00007FFFB366BBEC 0x00007FFF3B58BBEC
resolves to user32.dll +0xBBEC user32.dll +0xBBEC
seconds since start 588 4301
frame 1824 14726
The faulted-on address is inside user32.dll’s .text section (flags [-X], executable and NOT
writable), so a write there must fault. It resolves to the SAME module offset in both crashes under different ASLR bases, which rules out random heap corruption.
NOTE ON ONE INFERENCE, stated so it is not taken as measured: we did not have engine PDBs installed, so +0x10CADC is unsymbolicated, and our explanation for WHY the destination is a user32 code address (the freed TArray’s data pointer slot being reused by window-related data, e.g. a WNDPROC) is deduced from the address, not observed. Everything else above is read directly from the shipped 5.8 source and from the crash contexts.
Affects Versions
5.8
Platform(s)
Windows
For crash reports, include your callstack
CRASH REPORTER CALLSTACK
The Crash Reporter window was closed before the text could be copied. The block below is the portable callstack taken verbatim from CrashContext.runtime-xml (), which is the same data in module+offset form and is symbolicatable against the 5.8.1 build. Both crashes are included; every frame offset is identical between them.
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION writing address 0x00007fffb366bbec
— CRASH 1 (UECC-Windows-528A47314E8474B459153D940DB1EA03, PID 2340) —
UnrealEditor-D3D12RHI 0x00007ffeb3d10000 + 10cadc
UnrealEditor-D3D12RHI 0x00007ffeb3d10000 + 1317cb
UnrealEditor-SlateRHIRenderer 0x00007ffeb7950000 + 7df4d
UnrealEditor-SlateRHIRenderer 0x00007ffeb7950000 + 5776f
UnrealEditor-RenderCore 0x00007fff369b0000 + 12f50e
UnrealEditor-RenderCore 0x00007fff369b0000 + 12fd7e
UnrealEditor-RenderCore 0x00007fff369b0000 + 12dbab
UnrealEditor-SlateRHIRenderer 0x00007ffeb7950000 + 550c8
UnrealEditor-SlateRHIRenderer 0x00007ffeb7950000 + 35e87
UnrealEditor-RenderCore 0x00007fff369b0000 + 189758
UnrealEditor-RenderCore 0x00007fff369b0000 + 15c3fc
UnrealEditor-RenderCore 0x00007fff369b0000 + 1799e1
UnrealEditor-RenderCore 0x00007fff369b0000 + 18a003
UnrealEditor-Core 0x00007ffed1970000 + f5e1e
UnrealEditor-Core 0x00007ffed1970000 + e8bfe
UnrealEditor-Core 0x00007ffed1970000 + e8efe
UnrealEditor-RenderCore 0x00007fff369b0000 + 1a9ff9
UnrealEditor-RenderCore 0x00007fff369b0000 + 1aa734
UnrealEditor-Core 0x00007ffed1970000 + 8205b8
UnrealEditor-Core 0x00007ffed1970000 + 819ee5
KERNEL32 0x00007fffb3040000 + 2ccb7
ntdll 0x00007fffb3a40000 + aad6c
— CRASH 2 (UECC-Windows-243F0D31472CEBFFCE90DEB2AEDDF3FE, PID 23620) —
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION writing address 0x00007fff3b58bbec
UnrealEditor-D3D12RHI 0x00007ffec7e40000 + 10cadc
UnrealEditor-D3D12RHI 0x00007ffec7e40000 + 1317cb
UnrealEditor-SlateRHIRenderer 0x00007ffe42800000 + 7df4d
UnrealEditor-SlateRHIRenderer 0x00007ffe42800000 + 5776f
UnrealEditor-RenderCore 0x00007ffed0620000 + 12f50e
UnrealEditor-RenderCore 0x00007ffed0620000 + 12fd7e
UnrealEditor-RenderCore 0x00007ffed0620000 + 12dbab
UnrealEditor-SlateRHIRenderer 0x00007ffe42800000 + 550c8
UnrealEditor-SlateRHIRenderer 0x00007ffe42800000 + 35e87
UnrealEditor-RenderCore 0x00007ffed0620000 + 189758
UnrealEditor-RenderCore 0x00007ffed0620000 + 15c3fc
UnrealEditor-RenderCore 0x00007ffed0620000 + 1799e1
UnrealEditor-RenderCore 0x00007ffed0620000 + 18a003
UnrealEditor-Core 0x00007ffece250000 + f5e1e
UnrealEditor-Core 0x00007ffece250000 + e8bfe
UnrealEditor-Core 0x00007ffece250000 + e8efe
UnrealEditor-RenderCore 0x00007ffed0620000 + 1a9ff9
UnrealEditor-RenderCore 0x00007ffed0620000 + 1aa734
UnrealEditor-Core 0x00007ffece250000 + 8205b8
UnrealEditor-Core 0x00007ffece250000 + 819ee5
KERNEL32 0x00007fff3bf70000 + 2ccb7
ntdll 0x00007fff3c660000 + aad6c
Symbolic module-name stack as reported in CrashContext :
UnrealEditor_D3D12RHI
UnrealEditor_D3D12RHI
UnrealEditor_SlateRHIRenderer
UnrealEditor_SlateRHIRenderer
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_SlateRHIRenderer
UnrealEditor_SlateRHIRenderer
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_Core
UnrealEditor_Core
UnrealEditor_Core
UnrealEditor_RenderCore
UnrealEditor_RenderCore
UnrealEditor_Core
UnrealEditor_Core
kernel32
ntdll
Additional Notes
The narrowest fix is to clear the state on the path that currently leaks it: have
FSlateApplication::TakeScreenshot reset the renderer’s ScreenshotState before returning false, so arequest that was not serviced cannot outlive its caller’s buffer.
A more robust fix would stop ScreenshotState holding raw pointers into caller-owned memory: either have the renderer own the destination buffer and hand it back on completion, or key the pending request on a weak handle so a destroyed viewport invalidates it.
Clearing on viewport/window destruction would also close the recycled-allocation path, where a new FSlateViewportInfo lands at the address of the destroyed one and compares equal at SlateRHIRenderer.cpp:1180.