Skip to content

fix: launch crash on OS 27.2 betas from back-deployed Date <= / >= - #398

Open
bilipp wants to merge 1 commit into
mainfrom
fix/date-comparison-backdeploy-crash
Open

bilipp wants to merge 1 commit into
mainfrom
fix/date-comparison-backdeploy-crash

Conversation

@bilipp

@bilipp bilipp commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Problem

A user on iOS 27.2 beta (24B5089g) reported that after picking iCloud in the first-run sync choice, Lume 3.1.0 (build 37) no longer opens. The crash report:

  • EXC_BAD_ACCESS (SIGKILL) at 0x0, termination CODESIGNING / Invalid Page ("Failed to fault in a page with execute permissions")
  • frame 0 is 0x0, called from SportsRailPlanner.isInWindow(_:start:end:) ← SportsRailPlanner.fixtures ← PhoneSportsHomeRail.body
  • 0.6 s after launch, on every launch

iCloud isn't the bug. It restored the user's playlists, so launch now goes to Home, and the sports rail's first render runs a Date >=.

Root cause

The iOS/tvOS/macOS 27.2 SDKs (Xcode 27.2, 27B52) declare Foundation's Date <= and >= as:

@backDeployed(before: macOS 27.2, iOS 27.2, tvOS 27.2, watchOS 27.2, visionOS 27.2)
public static func >= (lhs: Date, rhs: Date) -> Bool

The back-deploy thunk calls the OS copy on any system that reports 27.2 or later, and its inlined fallback below that. Early 27.2 betas report 27.2 but don't export $s10Foundation4DateV2geoiySbAC_ACtFZ / …2leoiy…, so the weak import binds to NULL and the call jumps to address 0. Older releases (18, 26, 27.0, 27.1) take the fallback and are unaffected, as is the shipping 27.2.

The App Store build had no downloadable dSYM, so for symbolication I rebuilt v3.1.0 with the same Xcode build. Its code offsets match the crash exactly: +0x346980 is bl Date.>= and +0x9f3ff0 is the call into SportsRailPlanner.fixtures. nm -m on that binary shows both operators as weak external from Foundation, at 44 call sites in 21 files (EPG, recording, sports, downloads, widget export…), plus one in LumeWidgets.

Fix

  • LumeShared/Date+BackDeployedComparison.swift declares <= and >= on Date. LumeShared is compiled into the app, LumeWidgets and LumeTopShelf. A module's own declaration shadows the imported one with the same signature, so no call site links the weak symbol any more, including call sites added later. <, > and == were never back-deployed and still come from Foundation.
  • LumeTests/Helpers/Date+BackDeployedComparison.swift is a mirror copy. With @testable import Lume the test module sees both Lume's and Foundation's operators, and <= in WatchProgressWriterLiveTests became ambiguous. Its own copy shadows both.

Both files can go once the deployment target reaches 27.2.

Verification

  • Release builds pass for iOS, tvOS and macOS. nm -m … | grep -E 'DateV2(ge|le)oiy' finds nothing in Lume, LumeWidgets.appex (iOS) or LumeTopShelf.appex (tvOS); before the fix, Lume and LumeWidgets both had the weak import.
  • build-for-testing passes for the Lume scheme (LumeTests and LumeUITests) and for LumePerformance.
  • 63 date-heavy unit tests pass (RecordingServerStore*, SportsChannelResolver*, WatchProgressWriterLiveTests).
  • I have not reproduced the crash on a 27.2 beta device. The fix works by removing the weak import, and the nm check above confirms that.

The 27.2 SDKs declare Foundation's `Date <=` and `>=` as
`@backDeployed(before: 27.2)`. The back-deploy thunk calls the system copy
on anything reporting 27.2 or later, but early 27.2 betas don't export it,
so the weak import binds to NULL. 3.1.0 (build 37) jumped to 0x0 from the
Home sports rail (`SportsRailPlanner.isInWindow`) on its first render, so
the app crashed at every launch once a playlist existed (e.g. right after
iCloud restored one).

Declare both operators in LumeShared, which the app, the widgets and Top
Shelf compile. A module's own declaration shadows Foundation's, so no call
site links the weak symbol any more. LumeTests carries the same two:
`@testable import Lume` would otherwise make its date comparisons ambiguous.
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