FSlateApplication::DrawPrepass() can access invalid memory.

It’s possible for a member of the SlateWindows collection to have been deleted if it’s attached to a recently-destroyed actor. This loop then will pass an invalid SWindow reference to PrepassWindowAndChildren().

// Draw all windows
for (const TSharedRef<SWindow>& CurrentWindow : SlateWindows)
{
	PrepassWindowAndChildren(CurrentWindow);
}

Attempting to access it here inside PrepassWindowAndChildren() causes an exception:

if ( WindowToPrepass->IsVisible() && !WindowToPrepass->IsWindowMinimized() )

Hey KevODoom-

Can you explain how you’re calling / using this code? Please provide the setup / reproduction steps that cause the exception, as well as the exception that you’re getting. Any information you can provide to help us reproduce the behavior locally will be helpful.

Hi ,
As far as I’m able to ascertain, this is happening on a Widget Component I’m using for debug output on a character. The widget has been added directly to the character as a component, but I’m not completely clear on what happens to cause the issue. Next time I run into it, I’ll try to capture a callstack and whatever other information I can about exactly what’s going on. Sorry I don’t have better info for you yet!

I tried creating a project and adding a widget component to my character blueprint. I was unable to generate a crash from interacting with this component on my end. Let me know if you can provide the exact setup you’re using or if you’re able to provide a sample project demonstrating issue.

Hmm. It’s difficult to reproduce. Happens infrequently enough that I haven’t been able to nail down exactly where it’s failing.

Here’s more data from what I suspect to be the same issue or something similar:

Exception thrown:  access violation.
this->NativeWindow.Object->**** was nullptr. occurred

At this location:

/** @return true if the window is visible, false otherwise*/
bool SWindow::IsVisible() const
{
	return NativeWindow.IsValid() && NativeWindow->IsVisible();
}

Callstack:

>	UE4Editor-SlateCore.dll!SWindow::IsVisible() Line 1326	C++
 	UE4Editor-Slate.dll!PrepassWindowAndChildren(TSharedRef<SWindow,0> WindowToPrepass) Line 1336	C++
 	UE4Editor-Slate.dll!FSlateApplication::DrawPrepass(TSharedPtr<SWindow,0> DrawOnlyThisWindow) Line 1391	C++
 	UE4Editor-Slate.dll!FSlateApplication::PrivateDrawWindows(TSharedPtr<SWindow,0> DrawOnlyThisWindow) Line 1433	C++
 	UE4Editor-Slate.dll!FSlateApplication::DrawWindows() Line 1190	C++
 	UE4Editor-Slate.dll!FSlateApplication::TickApplication(ESlateTickType TickType, float DeltaTime) Line 1777	C++
 	UE4Editor-Slate.dll!FSlateApplication::Tick(ESlateTickType TickType) Line 1595	C++
 	UE4Editor.exe!FEngineLoop::Tick() Line 3378	C++
 	[Inline Frame] UE4Editor.exe!EngineTick() Line 62	C++
 	UE4Editor.exe!GuardedMain(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 166	C++
 	UE4Editor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 199	C++
 	[Inline Frame] UE4Editor.exe!invoke_main() Line 94	C++
 	UE4Editor.exe!__scrt_common_main_seh() Line 253	C++
 	kernel32.dll!00007ffe89d91fe4()	Unknown
 	ntdll.dll!00007ffe8c89ef91()	Unknown

Local contents:

-		this	0x00000226a2c7a090 {...}	const SWindow * {FSlateControlledConstruction}
+		[FSlateControlledConstruction]	{...}	FSlateControlledConstruction
+		SCompoundWidget	{ChildSlot={...} ContentScale={Value={X=1.00000000 Y=1.00000000 } bIsSet=true Getter=Unbound } ColorAndOpacity=...}	SCompoundWidget
		MoveResizeZone	-842150451	EWindowZone::Type
+		MoveResizeStart	{X=-431602080. Y=-431602080. }	FVector2D
+		MoveResizeRect	{Left=-1.00000000 Top=-1.00000000 Right=-1.00000000 ...}	FSlateRect
		Type	Normal (0)	EWindowType
+		Title	{Value={...} bIsSet=true Getter=Unbound }	TAttribute<FText>
		bDragAnywhere	false	bool
		Opacity	1.00000000	float
		SizingRule	UserSized (2 '\x2')	ESizingRule
		AutoCenterRule	PreferredWorkArea (2 '\x2')	EAutoCenter
		TransparencySupport	None (0)	EWindowTransparency
		bCreateTitleBar	false	bool
		bIsPopupWindow	false	bool
		bIsTopmostWindow	false	bool
		bSizeWillChangeOften	false	bool
		bInitiallyMaximized	false	bool
		bInitiallyMinimized	false	bool
		bHasEverBeenShown	true	bool
		bFocusWhenFirstShown	true	bool
		bHasOSWindowBorder	true	bool
		bVirtualWindow	false	bool
		bHasCloseButton	true	bool
		bHasMinimizeButton	true	bool
		bHasMaximizeButton	true	bool
		bHasSizingFrame	true	bool
		bIsModalWindow	false	bool
		bIsMirrorWindow	false	bool
		bShouldPreserveAspectRatio	false	bool
		WindowActivationPolicy	Always (1)	EWindowActivationPolicy
+		InitialDesiredScreenPosition	{X=160.000000 Y=225.000000 }	FVector2D
+		InitialDesiredSize	{X=1280.00000 Y=720.000000 }	FVector2D
+		ScreenPosition	{X=160.000000 Y=225.000000 }	FVector2D
+		PreFullscreenPosition	{X=0.000000000 Y=0.000000000 }	FVector2D
+		Size	{X=1280.00000 Y=720.000000 }	FVector2D
+		ViewportSize	{X=2160.00000 Y=1200.00000 }	FVector2D
+		Viewport	Ptr=0x00000226a5a79360, SharedRefs=-572662307, WeakRefs=-572662307, Object={CurrentReplyState={RequestedMousePos=Unset EventHandler=Null MouseCaptor=Null ...} KeyStateMap=Num=19 ...}	TWeakPtr<ISlateViewport,0>
		TitleBarSize	0.000000000	float
+		Morpher	{StartingOpacity=-431602080. TargetOpacity=-431602080. StartingMorphShape={Left=0.000000000 Top=0.000000000 ...} ...}	SWindow::FMorpher
		WindowZone	-842150451	EWindowZone::Type
+		TitleArea	Null	TSharedPtr<SWidget,0>
+		ContentSlot	0x00000226122b4680 {...}	SVerticalBox::FSlot *
+		WidgetToFocusOnActivate	Null	TWeakPtr<SWidget,0>
+		WidgetFocusedOnDeactivate	Null	TWeakPtr<SWidget,0>
+		Style	0x00000226525a0100 {MinimizeButtonStyle={Normal={ImageSize={X=27.0000000 Y=18.0000000 } Margin={Left=...} ...} ...} ...}	const FWindowStyle *
+		WindowBackground	0x00000226525a1080 {ImageSize={X=74.0000000 Y=74.0000000 } Margin={Left=0.000000000 Top=0.000000000 ...} ...}	const FSlateBrush *
+		SizeLimits	{MinWidth=Unset MinHeight=Unset MaxWidth=Unset ...}	FWindowSizeLimits
+		NativeWindow	Ptr=0x00000226a4e2e380, SharedRefs=0, WeakRefs=1, Object={Definition=Ptr=0xdddddddddddddddd, SharedRefs=???, WeakRefs=???, Object={Type=??? XDesiredPositionOnScreen=??? YDesiredPositionOnScreen=??? ...} }	TSharedPtr<FGenericWindow,0>
+		HittestGrid	Ptr=0x00000226a2a4abb0, SharedRefs=-572662308, WeakRefs=-572662307, Object={WidgetsCachedThisFrame=Ptr=0x00000226a2a4a1b0, SharedRefs=???, WeakRefs=???, Object=Invalid Cells=Invalid ...}	TSharedRef<FHittestGrid,0>
+		OnWindowActivated	Unbound	TBaseDelegate<void>
+		WindowActivatedEvent	{...}	TMulticastDelegate<void>
+		OnWindowDeactivated	Unbound	TBaseDelegate<void>
+		WindowDeactivatedEvent	{...}	TMulticastDelegate<void>
+		OnWindowClosed	Unbound	TBaseDelegate<void,TSharedRef<SWindow,0> const &>
+		OnWindowMoved	Unbound	TBaseDelegate<void,TSharedRef<SWindow,0> const &>
+		RequestDestroyWindowOverride	Unbound	TBaseDelegate<void,TSharedRef<SWindow,0> const &>
+		WindowOverlay	Ptr=0x00000226a4547c10, SharedRefs=-572662307, WeakRefs=-572662307, Object={Children=Invalid }	TSharedPtr<SOverlay,0>
+		PopupLayer	Ptr=0x00000226a4546c10, SharedRefs=-572662308, WeakRefs=-572662307, Object={Children=Invalid OwnerWindow=Ptr=0xdddddddddddddddd, SharedRefs=???, WeakRefs=???, Object={MoveResizeZone=??? MoveResizeStart={X=??? Y=??? } MoveResizeRect={Left=??? Top=??? Right=??? ...} ...} }	TSharedPtr<SPopupLayer,0>
+		FullWindowOverlayWidget	Null	TSharedPtr<SWidget,0>
+		ParentWindowPtr	Null	TWeakPtr<SWindow,0>
+		ChildWindows	Empty	TArray<TSharedRef<SWindow,0>,FDefaultAllocator>
+		OnWorldSwitchHack	Unbound	TBaseDelegate<int,int>
		bShouldShowWindowContentDuringOverlay	false	bool
		ExpectedMaxWidth	-1	int
		ExpectedMaxHeight	-1	int
+		TitleBar	Null	TSharedPtr<IWindowTitleBar,0>
+		LayoutBorder	{Left=5.00000000 Top=5.00000000 Right=5.00000000 ...}	FMargin
+		UserResizeBorder	{Left=5.00000000 Top=5.00000000 Right=5.00000000 ...}	FMargin
		bIsDrawingEnabled	true	bool
+		ActiveTimerHandle	Null	TWeakPtr<FActiveTimerHandle,0>

Wish I could give you more info on what exactly is getting it into this state. I don’t know if it matters, but this is occurring in a VR Preview session launched from editor into Vive.

Hope this helps!

Additional data:

Exception thrown:  access violation.
SWidget::GetChildren[virtual](...)->**** was 0xFFFFFFFFFFFFFFFF. occurred

At this location:

void SWidget::SlatePrepass(float LayoutScaleMultiplier)
{
	//SLATE_CYCLE_COUNTER_SCOPE_CUSTOM_DETAILED(SLATE_STATS_DETAIL_LEVEL_MED, GSlatePrepass, GetType());

	// TODO Figure out a better way than to just reset the pointer.  This causes problems when we prepass
	// volatile widgets, who still need to know about their invalidation panel in case they vanish themselves.

	// Reset the layout cache object each pre-pass to ensure we never access a stale layout cache object 
	// as this widget could have been moved in and out of a panel that was invalidated between frames.
	//LayoutCache = nullptr;

	if ( bCanHaveChildren )
	{
		// Cache child desired sizes first. This widget's desired size is
		// a function of its children's sizes.
		FChildren* MyChildren = this->GetChildren();
	--->	const int32 NumChildren = MyChildren->Num();
		for ( int32 ChildIndex=0; ChildIndex < NumChildren; ++ChildIndex )
		{
			const TSharedRef<SWidget>& Child = MyChildren->GetChildAt(ChildIndex);

			if ( Child->Visibility.Get() != EVisibility::Collapsed )
			{
				const float ChildLayoutScaleMultiplier = GetRelativeLayoutScale(MyChildren->GetSlotAt(ChildIndex), LayoutScaleMultiplier);
				// Recur: Descend down the widget tree.
				Child->SlatePrepass(LayoutScaleMultiplier * ChildLayoutScaleMultiplier);
			}
		}
	}

Callstack:

>	UE4Editor-SlateCore.dll!SWidget::SlatePrepass(float LayoutScaleMultiplier) Line 493	C++
 	UE4Editor-Slate.dll!PrepassWindowAndChildren(TSharedRef<SWindow,0> WindowToPrepass) Line 1343	C++
 	UE4Editor-Slate.dll!FSlateApplication::DrawPrepass(TSharedPtr<SWindow,0> DrawOnlyThisWindow) Line 1391	C++
 	UE4Editor-Slate.dll!FSlateApplication::PrivateDrawWindows(TSharedPtr<SWindow,0> DrawOnlyThisWindow) Line 1433	C++
 	UE4Editor-Slate.dll!FSlateApplication::DrawWindows() Line 1190	C++
 	UE4Editor-Slate.dll!FSlateApplication::TickApplication(ESlateTickType TickType, float DeltaTime) Line 1777	C++
 	UE4Editor-Slate.dll!FSlateApplication::Tick(ESlateTickType TickType) Line 1595	C++
 	UE4Editor.exe!FEngineLoop::Tick() Line 3378	C++
 	[Inline Frame] UE4Editor.exe!EngineTick() Line 62	C++
 	UE4Editor.exe!GuardedMain(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 166	C++
 	UE4Editor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 199	C++
 	[Inline Frame] UE4Editor.exe!invoke_main() Line 94	C++
 	UE4Editor.exe!__scrt_common_main_seh() Line 253	C++
 	kernel32.dll!00007ffe89d91fe4()	Unknown
 	ntdll.dll!00007ffe8c89ef91()	Unknown

Locals (unfortunately this was a development build):

+		this	0x000001fe21424b90 {...}	SWidget * {FSlateControlledConstruction}
		ChildIndex	Variable is optimized away and not available.	
		ChildLayoutScaleMultiplier	Variable is optimized away and not available.	
		LayoutScaleMultiplier	Variable is optimized away and not available.	
+		MyChildren	0x0000003ee1acd500 {...}	FChildren *
		NumChildren	Variable is optimized away and not available.	

Still not able to figure out exactly what’s going on to cause this. My earlier theory that it was a UMG widget on an AI-controlled character seems to have been incorrect, as there were no characters other than the player character in this environment. Hmm…

Looks like the DrawPrepass was happening on this object:

+		this	0x000001fe501fc100 {OnDragDropCheckOverride=Unbound CursorLock={PathToLockingWidget={Widgets=Num=5 Window=...} ...} ...}	FSlateApplication *

Callstacks don’t exactly match up, but it always seems to be doing roughly the same job when it runs into trouble.

My current operating theory is that it happens when the Vive temporarily loses tracking. Unconfirmed, but a theory.

Hi KevODoom,

It looks like you’re encountering UE-51720, which was fixed for the upcoming 4.19 release. Please let us know if you continue to see any of these crashes after 4.19 is released and we’ll look into it.

Best,

Cody