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

Fix GDI handle leak in Icon.DrawImage #47836

Merged
merged 5 commits into from
Feb 8, 2021
Merged

Conversation

safern
Copy link
Member

@safern safern commented Feb 4, 2021

Fixes: #46789

This was a regression from 3.1 -> 5.0 caused in: dotnet/corefx@f807df6

I will need to port this to 5.0 as this is affecting winforms costumers directly and apps could just die if we exceed the GDI+ handle limit.

@ghost
Copy link

ghost commented Feb 4, 2021

Tagging subscribers to this area: @safern, @tannergooding
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes: #46789

This was a regression from 3.1 -> 5.0 caused in: dotnet/corefx@f807df6

Author: safern
Assignees: -
Labels:

area-System.Drawing

Milestone: -

@ericstj
Copy link
Member

ericstj commented Feb 4, 2021

Could we test for this and maybe other leaks?

@safern
Copy link
Member Author

safern commented Feb 4, 2021

Could we test for this and maybe other leaks?

Let me think on some ideas with @JeremyKuhne how we can test this.

@JeremyKuhne
Copy link
Member

GetGuiResources should let you check on handle usage. You'd have to not run the regression test concurrently or kick it off out-of-proc. I haven't used this API myself yet, but given this regression I'm now committing some thought to it.

For 6.0 it might be worth considering introducing disposables to help ensure closure of handles. I call them "scopes" in WinForms, and I flip between disposable ref structs in release and finalizable classes in debug to help shake out where we didn't use them right (didn't put in a using). I found that the majority of usages in WinForms could be scoped to the stack with not much refactoring.

In rolling scopes out in WinForms I found a number of leaks, particularly in cases where we were trying to juggle more than one resource. It also fixed some ordering issues in those cases- ensuring we release in the reverse order of when they were acquired.

@safern
Copy link
Member Author

safern commented Feb 4, 2021

Maybe we can add a test for Icon.DrawIcon and then open a 6.0 issue to investigate if there are more memory leaks and probably do a small rewrite on places that we need to delete handles to use scopes as you did on winforms.

@safern
Copy link
Member Author

safern commented Feb 5, 2021

I added a test for this specific scenario. Validated that without the fix the test fails, for other possible leaks, I will open an issue to address for 6.0. PTAL.

@safern
Copy link
Member Author

safern commented Feb 5, 2021

Hmmm interesting that finalHandles is returning 0 when running on mono.

@ericstj
Copy link
Member

ericstj commented Feb 5, 2021

Hmmm interesting that finalHandles is returning 0 when running on mono.

Is it possible that the GC kicked in before that assertion and cleaned up all your unreferenced drawing types since they are no longer used in the rest of the method body? Maybe try adding GC.KeepAlive on them after the assertion.

@safern
Copy link
Member Author

safern commented Feb 5, 2021

Maybe try adding GC.KeepAlive on the them after the assertion.

I'll try that and see if that's it.

@safern safern mentioned this pull request Feb 6, 2021
@safern
Copy link
Member Author

safern commented Feb 6, 2021

Interesting, it was not the GC. It was an error on the native call to get the handle count as I was caching the current process handle and reusing it. Calling Process.GetCurrentProcess().Handle each time fixed the issue.

@ericstj
Copy link
Member

ericstj commented Feb 8, 2021

It was an error on the native call to get the handle count as I was caching the current process handle and reusing it. Calling Process.GetCurrentProcess().Handle each time fixed the issue.

Sounds like just another type of GC problem. Process itself is disposable, you captured the IntPtr handle but didn't keep Process rooted. So Process was finalized which closed the handle. This makes more sense, the GC had plenty of time to run while you were looping. A better fix would be to add a using for the Process.

@safern
Copy link
Member Author

safern commented Feb 8, 2021

Makes sense.

@MattGal
Copy link
Member

MattGal commented Feb 8, 2021

Not sure why Helix thinks these tests failed. I see all tests passing and runner returning 0.
https://dev.azure.com/dnceng/public/_build/results?buildId=983602&view=ms.vss-test-web.build-test-results-tab&runId=30817358&resultId=175855&paneView=attachments
https://dev.azure.com/dnceng/public/_build/results?buildId=983602&view=ms.vss-test-web.build-test-results-tab&runId=30817202&resultId=183737&paneView=attachments

Is something going on with Helix on OSX? cc @MattGal

Taking a look, @safern was just showing me some network flakiness on two mac work items and this may be them.

@MattGal
Copy link
Member

MattGal commented Feb 8, 2021

@ericstj yes these are the same two strange timeouts @safern showed me. Given the symptoms, it's most likely network flakiness in the lab where these macs are hosted while communicating with Event Hub (in such a way that it never returns). If it happens more than twice (or, say, on the same machines repeatedly) we can open up an issue on dotnet/core-eng to have DDFUN investigate the hardware.

One possible thing you could do quickly would be to stop using XUnit reporter by setting EnableXunitReporter=false, since the main workflow seems to look at test failures in AzDO anyways. This of course depends on whether folks still use this mode of test result analysis.

@safern
Copy link
Member Author

safern commented Feb 8, 2021

This of course depends on whether folks still use this mode of test result analysis.

Would disabling that, stop pushing results to Kusto? Cause we do use Kusto still for some things.

@safern safern merged commit b8db68c into dotnet:master Feb 8, 2021
@safern safern deleted the FixGdiHandleLeak branch February 8, 2021 20:45
@MattGal
Copy link
Member

MattGal commented Feb 8, 2021

This of course depends on whether folks still use this mode of test result analysis.

Would disabling that, stop pushing results to Kusto? Cause we do use Kusto still for some things.

yes, that's what XUnitReporter does.

@ghost ghost locked as resolved and limited conversation to collaborators Mar 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[NET 5.0] GDI resource leak in Graphics.DrawIcon method
4 participants