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 Reference Exception: System.Windows.Forms.TabControl.<WmSelChange> #12661

Open
StuB-85 opened this issue Dec 19, 2024 · 3 comments
Open
Assignees
Labels
💥 regression-release Regression from a public release
Milestone

Comments

@StuB-85
Copy link

StuB-85 commented Dec 19, 2024

.NET version

.NET 8.0
SDK: 8.0.403
RUNTIME: 8.0.10

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

TabControl crashes due to null reference exception. This can occur after all tabs are removed while TabControl.AccessibilityObject is not null.

 	System.Windows.Forms.dll!System.Windows.Forms.TabControl.WmSelChange.AnonymousMethod__214_0()	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj)	Unknown
 	System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks()	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.TabControl.WndProc(ref System.Windows.Forms.Message m)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(Windows.Win32.Foundation.HWND hWnd, Windows.Win32.MessageId msg, Windows.Win32.Foundation.WPARAM wparam, Windows.Win32.Foundation.LPARAM lparam)	Unknown
 	[Native to Managed Transition]	
 	[Managed to Native Transition]	
 	System.Windows.Forms.Primitives.dll!Windows.Win32.PInvoke.DispatchMessage(Windows.Win32.UI.WindowsAndMessaging.MSG* lpMsg)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.Microsoft.Office.IMsoComponentManager.FPushMessageLoop(nuint dwComponentID, Microsoft.Office.msoloop uReason, void* pvLoopData)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Microsoft.Office.msoloop reason, System.Windows.Forms.ApplicationContext context)	Unknown
 	System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Microsoft.Office.msoloop reason, System.Windows.Forms.ApplicationContext context)	Unknown
>	WmSelIssue.dll!WmSelIssue.Program.Main() Line 14	C#

Steps to reproduce

  1. Unzip solution and open in visual studio.
  2. Build and Run.
  3. Click either of the repro buttons.
  4. Observe the crash.

WmSelIssue.zip

@StuB-85 StuB-85 added the untriaged The team needs to look at this issue in the next triage label Dec 19, 2024
@elachlan
Copy link
Contributor

private bool WmSelChange()
{
TabControlCancelEventArgs tcc = new(SelectedTab, SelectedIndex, false, TabControlAction.Selecting);
OnSelecting(tcc);
if (!tcc.Cancel)
{
OnSelected(new TabControlEventArgs(SelectedTab, SelectedIndex, TabControlAction.Selected));
OnSelectedIndexChanged(EventArgs.Empty);
if (IsAccessibilityObjectCreated && SelectedTab?.ParentInternal is TabControl)
{
SelectedTab.TabAccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_SelectionItem_ElementSelectedEventId);
BeginInvoke((MethodInvoker)(() => SelectedTab.TabAccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId)));
}
}
else
{
// user Cancelled the Selection of the new Tab.
PInvokeCore.SendMessage(this, PInvoke.TCM_SETCURSEL, (WPARAM)_lastSelection);
UpdateTabSelection(true);
}
return tcc.Cancel;
}

Maybe we need to change the code to do a null check on the SelectedTab?

SelectedTab?.TabAccessibilityObject

@Olina-Zhang can your team test the issue please?

@John-Qiao
Copy link
Member

@elachlan I tried your suggestion to do a null check on the SelectedTab? in 1959 and 1960 lines, it can fix the crash issue in demo project.

Image

testresult.mp4

@Tanya-Solyanik
Copy link
Member

Tanya-Solyanik commented Dec 20, 2024

@StuB-85 - thank you for reporting this issue! Do you require this fix in NET8?

@elachlan - thank you for jumping on this bug!

@John-Qiao - thank you, please go ahead with the PR, and add a unit test based on the customer project. Also please add to the bug description what versions this repros on, if this is a regression and what change had introduced it, this info will help with the servicing decision.
This code is not present on .NET Framework, so this is a regression in .NET - https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/TabControl.cs,2070

Please work with @LeafShi1's team while the Redmond team is on the holidays.
Only line 1960 needs a ? - this function is executed asynchronously and by the time it is executed, we might have nulled-out the SelectedTab. Line 1959 is executed right after we check that SelectedTab is not null and controls are not accessed from other threads because cross-thread access to windows handles throws on windows level, so we know the tab is still not null.
We should additionally test the following conditions inside the delegate to guard against the case that the tab have been unparented, or accessibility objects were disposed (we don't want to recreate them or they would leak):
if (IsAccessibilityObjectCreated && SelectedTab?.ParentInternal is TabControl)

@Tanya-Solyanik Tanya-Solyanik removed the untriaged The team needs to look at this issue in the next triage label Dec 20, 2024
@Tanya-Solyanik Tanya-Solyanik added this to the 10.0 Preview1 milestone Dec 20, 2024
@Tanya-Solyanik Tanya-Solyanik added the 💥 regression-release Regression from a public release label Dec 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💥 regression-release Regression from a public release
Projects
None yet
Development

No branches or pull requests

4 participants