Skip to content

Bugfix: Avoid potential crash from force-unwrap of pointOrigin in pan gesture#33897

Open
rm335 wants to merge 1 commit into
mozilla-mobile:mainfrom
rm335:bugfix/etp-pointorigin-force-unwrap
Open

Bugfix: Avoid potential crash from force-unwrap of pointOrigin in pan gesture#33897
rm335 wants to merge 1 commit into
mozilla-mobile:mainfrom
rm335:bugfix/etp-pointorigin-force-unwrap

Conversation

@rm335
Copy link
Copy Markdown

@rm335 rm335 commented May 19, 2026

💡 Description

Fixes a potential crash in the Tracking Protection menus where pointOrigin! was force-unwrapped inside panGestureRecognizerAction(sender:). The property is optional and only initialized in viewDidLayoutSubviews, so if the pan gesture fires before the first layout pass (e.g. after a memory warning, a rapid present/dismiss cycle, or in automated UI tests) the app crashes with EXC_BAD_INSTRUCTION.

The same bug pattern existed in two files (duplicated code path):

  • firefox-ios/Client/Frontend/Browser/EnhancedTrackingProtection/EnhancedTrackingProtectionVC.swift — line 495
  • firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionViewController.swift — line 707

The fix

The force-unwrap is replaced with the same safe-fallback pattern the surrounding code already uses just a few lines later (L504 / L716), defaulting to the current view origin (originalYPosition) when pointOrigin has not yet been set:

// Before
view.frame.origin = CGPoint(x: originalXPosition,
                            y: self.pointOrigin!.y + translation.y)

// After
view.frame.origin = CGPoint(x: originalXPosition,
                            y: (self.pointOrigin?.y ?? originalYPosition) + translation.y)

Behavior is identical in the common case where pointOrigin has been initialized (which is the only case the previous code handled correctly). Only the previously-crashing edge case is corrected.

Regression tests

Two new test files exercise the gesture handler with pointOrigin still nil (i.e. before viewDidLayoutSubviews ran) and verify the call no longer crashes:

  • firefox-ios/firefox-ios-tests/Tests/ClientTests/TrackingProtectionTests/EnhancedTrackingProtectionVCTests.swift
  • firefox-ios/firefox-ios-tests/Tests/ClientTests/TrackingProtectionTests/TrackingProtectionViewControllerTests.swift

Both test files follow the existing TrackingProtectionTests test-suite pattern (XCTest, @MainActor, @testable import Client, DependencyHelperMock().bootstrapDependencies()) and use a MockPanGestureRecognizer test double to drive the handler deterministically.

🎥 Demos

N/A — no visual change. Behavior is identical when pointOrigin is set (the common case). Only the previously-crashing edge case is corrected.

Static-grep verification
$ grep -rn "pointOrigin!" firefox-ios/Client --include="*.swift"
# (no output -- 0 hits)

📝 Checklist

  • I filled in the ticket numbers and a description of my work
  • I updated the PR name to follow our PR naming guidelines
  • I ensured unit tests pass and wrote tests for new code
  • If working on UI, I checked and implemented accessibility (Dynamic Text and VoiceOver) — N/A (no visible UI change)
  • If adding telemetry, I read the data stewardship requirements and will request a data review — N/A
  • If adding or modifying strings, I read the guidelines and will request a string review from l10n — N/A
  • If needed, I updated documentation and added comments to complex code — no new code comments needed; fix uses the existing pattern from elsewhere in the same file.

@rm335 rm335 requested a review from a team as a code owner May 19, 2026 18:07
@rm335 rm335 requested a review from ih-codes May 19, 2026 18:07
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.

1 participant