dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.4k stars 976 forks source link

DetachContextMenuStrip pattern can lead to memory leaks #12353

Open kirsan31 opened 4 days ago

kirsan31 commented 4 days ago

.NET version

All up to .Net9.

Did it work in .NET Framework?

No

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

No.

Issue description

This null out ContextMenuStrip pattern:

private void DetachContextMenuStrip(object? sender, EventArgs e) => ContextMenuStrip = null;

// And ContextMenuStrip.Set` property:
EventHandler disposedHandler = new(DetachContextMenuStrip);

if (oldValue is not null)
{
    oldValue.Disposed -= disposedHandler;
}

if (value is not null)
{
    value.Disposed += disposedHandler;
}

Can lead to memory leaks. Using in 3 places:

  1. Control https://github.com/dotnet/winforms/blob/d1986025b2dafdcc3aeda0505da37e580bb3d82e/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs#L1232 More or less justified, since control in most cases lives either as long as the menu, or longer. But I didn't find a ContextMenuStrip.Disposed -= disposedHandler; code in Control.Dispose. So if ContextMenuStrip will outlive control (and user not null out ContextMenuStrip property) - we will have memory leak (control will remain in memory) at any case.
  2. DataGridViewBand and DataGridViewCell https://github.com/dotnet/winforms/blob/1f2d238fe75b40408de8d3cd6ca363df3615132f/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewBand.cs#L59 https://github.com/dotnet/winforms/blob/1f2d238fe75b40408de8d3cd6ca363df3615132f/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCell.cs#L117 Here it probably does more harm than good, since DataGridView elements in most cases live less than the menu and they never disposed.

My thots are:

Steps to reproduce

DetachContextMenuStripLeaks.zip

elachlan commented 3 days ago

@LeafShi1 can your team please test this?

kirsan31 commented 3 days ago

@elachlan DataGridView case (point 2) was tested in #6859. I will adapt repro app to test also point 1...

---------------------UPD---------------------

Updated 1 post with repro app and instructions.

LeafShi1 commented 7 hours ago

@LeafShi1 can your team please test this?

This problem does exist Image