Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NULL HWND's attempted to be parented under SystemResources listener window cause unhanded exception #2089

Closed
vatsan-madhavan opened this issue Oct 22, 2019 · 3 comments
Assignees
Labels
Bug Product bug (most likely) issue-type-netfx-port Ports from .NET Framework regression status: This issue is a regression from a previous build or release tenet-reliability Reliability related issue
Milestone

Comments

@vatsan-madhavan
Copy link
Member

When an HwndHost receives SourceChanged event, it goes through BuildOrReparentWindow. When the hosted window is invisible, it is usually reparented under a temporary windows maintained by WPF in the SystemResources class, until later on the window can be rebuilt and parented back to a valid parent.

There is a latent bug in this logic where in NULL HWND's are attempted to be parented to SystemResources managed temporary windows. This bug goes back quite a while (.NET 4.5 likely). WPF seems to ignore the return value from kernel32!SetParent and not deal with this failure. This has not been a crashing failure until now.

Starting .NET 4.8, there have been some changes to this codepath that have resulted in this bug becoming a crashing bug. In addition to calling kernel32!SetParent on a NULL HWND, WPF attempts to perform several other operations on the HWND, including querying its DPI characteristics (which returns invalid information). Once of the subsidiary steps returns an invalid value that in turn results in a crash with the following stack:

System.Collections.Generic.KeyNotFoundException: 'The given key was not present in the dictionary.'
mscorlib.dll!System.Collections.Generic.Dictionary<System.__Canon, System.__Canon>.this[System.__Canon].get(System.__Canon key) Line 183	C#
 	PresentationFramework.dll!System.Windows.SystemResources.GetDpiAwarenessCompatibleNotificationWindow(System.Runtime.InteropServices.HandleRef hwnd) Line 1731	C#
 	PresentationFramework.dll!System.Windows.Interop.HwndHost.BuildOrReparentWindow() Line 1196	C#
 	PresentationFramework.dll!System.Windows.Interop.HwndHost.OnSourceChanged(object sender, System.Windows.SourceChangedEventArgs e) Line 1077	C#
 	PresentationCore.dll!System.Windows.SourceChangedEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) Line 142	C#
 	PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) Line 341	C#
 	PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) Line 81	C#
 	PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) Line 203	C#
 	PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) Line 2354	C#
 	PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs e) Line 432	C#
 	PresentationCore.dll!System.Windows.PresentationSource.UpdateSourceOfElement(System.Windows.DependencyObject doTarget, System.Windows.DependencyObject doAncestor, System.Windows.DependencyObject doOldParent) Line 861	C#
 	PresentationCore.dll!System.Windows.PresentationSource.RootChanged(System.Windows.Media.Visual oldRoot, System.Windows.Media.Visual newRoot) Line 566	C#
 	PresentationCore.dll!System.Windows.Interop.HwndSource.RootVisualInternal.set(System.Windows.Media.Visual value) Line 699	C#
 	PresentationCore.dll!System.Windows.Interop.HwndSource.Dispose(bool disposing) Line 2895	C#	
 	PresentationCore.dll!System.Windows.Interop.HwndSource.OnHwndDisposed(object sender, System.EventArgs args) Line 2819	C#
 	WindowsBase.dll!MS.Win32.HwndWrapper.Dispose(bool disposing, bool isHwndBeingDestroyed) Line 230	C#
 	WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Line 360	C#
 	WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Line 494	C#
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 104	C#
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Line 37	C#
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Line 1445	C#
 	WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line 398	C#

This issue is related to, but not a duplicate of, #1198/#1953. That said, it affects the same sorts of scenarios described in #1198.

// ****BUG*** 
// unconditional else block
// hwnd.Handle could be IntPtr.Zero, bad things can happen here
// ****BUG*** 

else
{
// Reparent the window to notification-only window provided by SystemResources
// This keeps the child window around, but it is not visible. We can reparent the
// window later when a new parent is available
var hwnd = SystemResources.GetDpiAwarenessCompatibleNotificationWindow(_hwnd);
UnsafeNativeMethods.SetParent(_hwnd, new HandleRef(null, hwnd.Handle));
// ...But we have a potential problem: If the SystemResources listener window gets
// destroyed ahead of the call to HwndHost.OnDispatcherShutdown(), the HwndHost's window
// will be destroyed too, before the "logical" Dispose has had a chance to do proper
// shutdown. This turns out to be very significant for WebBrowser/ActiveXHost, which shuts
// down the hosted control through the COM interfaces, and the control destroys its
// window internally. Evidently, the WebOC fails to do full, proper cleanup if its
// window is destroyed unexpectedly.
// To avoid this situation, we make sure SystemResources responds to the Dispatcher
// shutdown event after this HwndHost.
SystemResources.DelayHwndShutdown();
}
}

@teh173
Copy link

teh173 commented Nov 21, 2019

@vatsan-madhavan Our native C++/WPF app with per-monitor v2, besides experiencing some of the crashes similar to the above, also seems to be experiencing some crashes with a slightly different call stack than some of the other reported issues I've seen. Is this a distinct issue that should be filed, or are multiple issues being addressed?

>	KERNELBASE.dll!RaiseException�()	Unknown
 	[Managed to Native Transition]	
 	PresentationCore.dll!MS.Internal.DpiUtil.HwndDpiInfo.NearestMonitorInfoFromWindow(System.IntPtr hwnd)	Unknown
 	PresentationCore.dll!MS.Internal.DpiUtil.HwndDpiInfo.HwndDpiInfo(System.IntPtr hWnd, bool fallbackToNearestMonitorHeuristic)	Unknown
 	PresentationFramework.dll!System.Windows.SystemResources.GetDpiAwarenessCompatibleNotificationWindow(System.Runtime.InteropServices.HandleRef hwnd)	Unknown
 	PresentationFramework.dll!System.Windows.Interop.HwndHost.BuildOrReparentWindow()	Unknown
 	PresentationFramework.dll!System.Windows.Interop.HwndHost.OnSourceChanged(object sender, System.Windows.SourceChangedEventArgs e)	Unknown
 	PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target)	Unknown
 	PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs)	Unknown
 	PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args)	Unknown
 	PresentationCore.dll!System.Windows.PresentationSource.UpdateSourceOfElement(System.Windows.DependencyObject doTarget, System.Windows.DependencyObject doAncestor, System.Windows.DependencyObject doOldParent)	Unknown
 	PresentationCore.dll!System.Windows.PresentationSource.RootChanged(System.Windows.Media.Visual oldRoot, System.Windows.Media.Visual newRoot)	Unknown
 	PresentationCore.dll!System.Windows.Interop.HwndSource.RootVisualInternal.set(System.Windows.Media.Visual value)	Unknown
 	PresentationCore.dll!System.Windows.Interop.HwndSource.Dispose(bool disposing)	Unknown
 	PresentationCore.dll!System.Windows.Interop.HwndSource.OnHwndDisposed(object sender, System.EventArgs args)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.Dispose(bool disposing, bool isHwndBeingDestroyed)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)	Unknown
 	[Native to Managed Transition]	
 	user32.dll!UserCallWinProcCheckWow()	Unknown
 	user32.dll!DispatchClientMessage()	Unknown
 	user32.dll!__fnNCDESTROY�()	Unknown
 	ntdll.dll!KiUserCallbackDispatcherContinue�()	Unknown
 	win32u.dll!NtUserDestroyWindow�()	Unknown
 	[Managed to Native Transition]	
 	WindowsBase.dll!MS.Win32.HwndWrapper.DestroyWindow(object args)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.Dispose(bool disposing, bool isHwndBeingDestroyed)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.Dispose()	Unknown
 	PresentationCore.dll!System.Windows.Interop.HwndSource.Dispose(bool disposing)	Unknown
 	PresentationCore.dll!System.Windows.Interop.HwndSource.Dispose()	Unknown
 	PresentationFramework.dll!System.Windows.Controls.Primitives.Popup.PopupSecurityHelper.DestroyWindow(System.Windows.Interop.HwndSourceHook hook, System.Windows.AutoResizedEventHandler onAutoResizedEventHandler, System.Windows.HwndDpiChangedEventHandler onDpiChagnedEventHandler)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.Primitives.Popup.DestroyWindow()	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherTimer.FireTick(object unused)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 980	C#
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 928	C#
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 917	C#
 	WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)	Unknown
 	[Native to Managed Transition]	
 	user32.dll!UserCallWinProcCheckWow()	Unknown
 	user32.dll!DispatchMessageWorker()	Unknown
 	[Frames may be missing, no binary loaded for mfc140u.dll]	
 	mfc140u.dll!00007ff9934a8f82()	Unknown

@vatsan-madhavan
Copy link
Member Author

@teh173 please open a new issue for this one. if possible, share a minimal repro app and a crash dump so we can investigate further.

@teh173
Copy link

teh173 commented Nov 25, 2019

Filed #2239

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Product bug (most likely) issue-type-netfx-port Ports from .NET Framework regression status: This issue is a regression from a previous build or release tenet-reliability Reliability related issue
Projects
None yet
Development

No branches or pull requests

2 participants