Skip to content

Conversation

@gribunin
Copy link
Contributor

When a window is created in a Tuari application with, for example, call to new WebviewWindow from the Javascript code and later is closed -- exactly 1 GDI object leaks. This happens because of the function set_drag_hwnd_rgn where 2 regions are created, one of them becomes managed by Windows after call to SetWindowRgn but another one remains dangling. Added correct release of the region handle after it is not used anymore.

@gribunin gribunin requested a review from a team as a code owner September 23, 2025 12:23
@github-project-automation github-project-automation bot moved this to 📬Proposal in Roadmap Sep 23, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Sep 23, 2025

Package Changes Through f851307

There are 9 changes which include @tauri-apps/api with minor, tauri-cli with minor, tauri-utils with minor, tauri-runtime-wry with minor, tauri-runtime with minor, tauri with minor, tauri-bundler with minor, @tauri-apps/cli with minor, tauri-macros with patch

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@tauri-apps/api 2.8.0 2.9.0
tauri-utils 2.7.0 2.8.0
tauri-bundler 2.6.1 2.7.0
tauri-runtime 2.8.0 2.9.0
tauri-runtime-wry 2.8.1 2.9.0
tauri-codegen 2.4.0 2.4.1
tauri-macros 2.4.0 2.4.1
tauri-plugin 2.4.0 2.4.1
tauri-build 2.4.1 2.4.2
tauri 2.8.5 2.9.0
@tauri-apps/cli 2.8.4 2.9.0
tauri-cli 2.8.4 2.9.0

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector


CombineRgn(Some(hrgn1), Some(hrgn1), Some(hrgn2), RGN_DIFF);

DeleteObject(hrgn2.into());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed as HRGN type implements the Free trait, which means it automatically calls DeleteObject on drop

Are you sure this leaked? If so, can you give me instructions that I can use to reproduce and inspect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It implements Free trait but not Drop trait. As far as I understand that means that there are two patterns in windows-rs:

Raw handle:
If you’re just holding an HRGN, nothing will free it automatically. You must call DeleteObject yourself.

Owning handle wrapper:
If you wrap it in something like Owned or Option<Owned>, then the Drop implementation of Owned calls Free::free automatically, so the handle is released when it goes out of scope.

In our case CreateRectRgn return HRGN and it's not released automatically.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, in that case I think we should probably just wrap it in Owned then like this

Owned::new(CreateRectRgn(...));

so that we don't need to worry about which method we should call to free an object since the Free trait already does that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just hrgn2.free(), I guess.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but Owned is better so it is freed at the end of scope implicitly using the Drop trait which is more aligned with Rust

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And while you are there you can add some other fix of much less importance, actually just in case of pure art. Theoretically if SetWindowRgn fails the hrgn1 GDI object would also will leak in this function as it's not owned by Windows. Better to write it as:

if !SetWindowRgn(hwnd, Some(hrgn1), true).as_bool() {
        // If it fails, we must free hrgn1 manually
        hrgn1.free();
    }

In practice if SetWindowRgn fails something much more worse than GDI leak happens of course.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah sounds good to me, feel free to update that as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, done

amrbashir
amrbashir previously approved these changes Sep 24, 2025
Copy link
Member

@amrbashir amrbashir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@amrbashir amrbashir merged commit b0c493a into tauri-apps:dev Sep 24, 2025
19 checks passed
@github-project-automation github-project-automation bot moved this from 📬Proposal to 🔎 In audit in Roadmap Sep 24, 2025
@gribunin gribunin deleted the fix/gdi-handle-leak branch September 24, 2025 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🔎 In audit

Development

Successfully merging this pull request may close these issues.

2 participants