Skip to content

fix(apple): Correctly handle stopTunnel and completionHandlers - #9308

Merged
jamilbk merged 5 commits into
mainfrom
fix/apple-completion-handler
May 30, 2025
Merged

fix(apple): Correctly handle stopTunnel and completionHandlers#9308
jamilbk merged 5 commits into
mainfrom
fix/apple-completion-handler

Conversation

@jamilbk

@jamilbk jamilbk commented May 30, 2025

Copy link
Copy Markdown
Member

This PR fixes two crashes related to lifetimes on Apple:

  • completionHandler was being called from within a Task executor context, which could be different from the one the IPC call was received on
  • The getLogFolderSize task could return and attempt to call completionHandler after the PacketTunnelProvider deinit'd
  • We were calling the completionHandler from stopTunnel manually. Apple explicitly says not to do this. Instead, we must call cancelTunnelWithError(nil) when we want to stop the tunnel from e.g. the onDisconnect. Apple with then call our stopTunnel override. The downside is that we have no control over the NEProviderStopReason received in this callback, but we don't use it anyway. Instead, we write the reason to a temporary file and read it from the GUI process when we detect a status change to disconnected. When that occurs, we're able to show a UI notification (macOS only - iOS can show this notification from the PacketTunnelProvider itself).

Copilot AI review requested due to automatic review settings May 30, 2025 17:04
@vercel

vercel Bot commented May 30, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
firezone ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 30, 2025 6:47pm

@jamilbk
jamilbk requested a review from thomaseizinger May 30, 2025 17:05
@jamilbk
jamilbk enabled auto-merge May 30, 2025 17:05
@jamilbk

jamilbk commented May 30, 2025

Copy link
Copy Markdown
Member Author

Tested on macOS / iOS.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR ensures that handleAppMessage and its completionHandler invocations always run on the MainActor, preventing potential pointer invalidation across different executor contexts.

  • Mark handleAppMessage as @MainActor
  • Wrap completionHandler calls in MainActor.run to enforce same actor context
Comments suppressed due to low confidence (2)

swift/apple/FirezoneNetworkExtension/PacketTunnelProvider.swift:178

  • [nitpick] Redundant actor hop: since handleAppMessage is already @MainActor and Task inherits that context, you can invoke completionHandler?(nil) directly without MainActor.run.
await MainActor.run { completionHandler?(nil) }

swift/apple/FirezoneNetworkExtension/PacketTunnelProvider.swift:249

  • [nitpick] Similarly, completionHandler?(data) can be called directly within the @MainActor context instead of wrapping it in MainActor.run.
await MainActor.run { completionHandler?(data) }

let data = withUnsafeBytes(of: size) { Data($0) }

completionHandler?(data)
// Ensure completionHandler is called on the same queue as handleAppMessage

Copilot AI May 30, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] The comment refers to a "queue", but this change is about actor isolation. Consider updating it to mention the MainActor context for clarity.

Copilot uses AI. Check for mistakes.
@sentry

sentry Bot commented May 30, 2025

Copy link
Copy Markdown

Sentry Issue: APPLE-CLIENT-5J

@jamilbk

jamilbk commented May 30, 2025

Copy link
Copy Markdown
Member Author

I'm not sure this is the actual cause of the issue, but it is one issue.

@jamilbk

jamilbk commented May 30, 2025

Copy link
Copy Markdown
Member Author

The other (minor) issue is that Task closure could return after the PacketTunnelProvider instance had deinit'd, which would cause something like this.

@jamilbk jamilbk changed the title fix(apple): ensure IPC and completionHandler same thread fix(apple): Correctly handle stopTunnel and completionHandlers May 30, 2025
@sentry

sentry Bot commented May 30, 2025

Copy link
Copy Markdown

Sentry Issue: APPLE-CLIENT-5F


func signOut() async throws {
try await sendMessageWithoutResponse(ProviderMessage.signOut)
try stop()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

When explicitly requested by the user, we call stopTunnel from this side of the IPC, which is what Apple says to do.

{/* When you cut a release, remove any solved issues from the "known issues" lists over in `client-apps`. This must not be done when the issue's PR merges. */}
<Unreleased>
<ChangeItem pull="9308">
Fixes a minor crash in the network extension that could occur when

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think there is such a thing as a minor crash. Maybe change that to rare?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah I can update it. The crash only reliably occurred during sign out, so no user impact.

@jamilbk
jamilbk added this pull request to the merge queue May 30, 2025
Merged via the queue into main with commit 889c1a9 May 30, 2025
@jamilbk
jamilbk deleted the fix/apple-completion-handler branch May 30, 2025 21:06
@sentry

sentry Bot commented May 31, 2025

Copy link
Copy Markdown

Sentry Issue: APPLE-CLIENT-5G

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.

3 participants