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(macos): Prevent NSExceptions when dropping a webview with registered protocols #1215

Merged
merged 5 commits into from
Apr 15, 2024

Conversation

FabianLars
Copy link
Member

@FabianLars FabianLars commented Apr 5, 2024

fixes tauri-apps/tauri#7898

This one was quiet hard to fix, i really tried to not rely on a global variable but always ended up with either nsexceptions or stack traces for invalid memory access. The problem is that when you're dropping the webview, like tauri does on window close, is that protocol handlers may still be running. In Tauri this is even more of an issue because it uses a protocol for the whole IPC implementation so even the close-requested event will cause problems here.

If the webview is dropped before the handler finished, either _webview or task (or both) will be undefined, but in a way that objc's is_null still returns false, but if you check its class it will be returned as nil. Relying on that unfortunetely doesn't work because it requires 2 calls to the object / class (first to get the class, second to get the class name) and the second one really often causes memory issues. Also the timing is unpredictable, sometimes it fails on the didReceive call, sometimes on the didFinish call, rarely on the didReceiveResponse call.

Since wry consumers can't know when the handler was finished (especially the responder part inside wry) i believe it would be unreasonable to expect users to make sure handlers are done before dropping the webview and instead it's something we should make sure.


P.S. I kinda hope someone comes up with a better solution because i'm not the biggest fan of the global webview vec myself, it's just the only thing i found that works reliably.

P.P.S. Also semi related to #1214 which is why i'm opening this pr right now and not waiting for tomorrow morning 🙃


Edit: Another thing that just came to mind, which i didn't investigate is whether returning early from the function will leak memory? For example the NSData instance when we don't end up calling didReceive. Even if this leaks memory, i'm not sure how to handle that in objc so some input on that topic would be appreciated :)

@FabianLars FabianLars requested a review from a team as a code owner April 5, 2024 20:53
src/wkwebview/mod.rs Outdated Show resolved Hide resolved
@pewsheen
Copy link
Contributor

pewsheen commented Apr 8, 2024

Is #1214 handling the same issue? I would prefer the fix here and just check if the webview_id is still on the running list.

@FabianLars
Copy link
Member Author

Is #1214 handling the same issue? I would prefer the fix here and just check if the webview_id is still on the running list.

No. My PR fixes a panic/mem issue when the InnerWebview struct is dropped while protocols are registered.

1214 fixes an issue when the dev aborts a request to a protocol via AbortHandler for example (a page reload may causes this too). This will make wkwebview send the stopTask event which is not triggered for the issue i'm trying to fix here.
For 1214 i do still think we should rustify it a bit more and use Lazy (like i said in the comment over there), if we end up using the PR.

src/wkwebview/mod.rs Outdated Show resolved Hide resolved
@FabianLars
Copy link
Member Author

don't mind the last commits, i'm so done for today 😂

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.

I think the reason is is_null still returns false is that because it is not set to std::ptr::null, I have seen a similar issue in #1206

I think we should fix it like this:

  1. pass the webview pointer to the responder closure
  2. when dropping the webview, we explicitly set the value at the webview ptr address to a null ptr or just a unit (`()``
  3. check inside the responder if the value pointed by the webview ptr is null

@FabianLars
Copy link
Member Author

Thank you, i'll see if i can make that work.

@FabianLars
Copy link
Member Author

Hmm, i may be doing something wrong, but i can't make it work like this. It also looks like the webview in the start_task and the one in drop point to different addresses.

@amrbashir
Copy link
Member

cc @wusyong

@wusyong
Copy link
Member

wusyong commented Apr 15, 2024

@lucasfernog Are you sure it's working? I believe @FabianLars mentioned it didn't work as intended.

@FabianLars
Copy link
Member Author

The PR's current implementation works for me.
I just couldn't make Amr's suggestion work (didn't push anything to the branch to not break the PR).

@wusyong
Copy link
Member

wusyong commented Apr 15, 2024

Ah sorry for the misunderstanding.

@wusyong wusyong merged commit 3e3d59c into dev Apr 15, 2024
12 checks passed
@wusyong wusyong deleted the fix/nsexception-on-drop branch April 15, 2024 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[bug] Crash when closing a window NSException
5 participants