Skip to content

Widget app extension: .appex binary is empty (dead-stripped) and the extension crashes in ExtensionFoundation on launch #313

Open

Description

@Victor2411-hub

Description

Building a WidgetKit app extension with xtool produces an .appex whose binary
is empty (no __text). Once the entry point is corrected so the widget code
is retained, the extension launches but crashes inside Apple's
ExtensionFoundation
before any widget is registered.

Both are reproducible with the repo's own example at Examples/DemoExtensions.

  1. Empty .appex binary. Packer emits -e _NSExtensionMain for every app
    extension. _NSExtensionMain comes from Foundation, so the linker resolves
    the entry point outside the binary and drops all objects from the widget's
    .library product. The appex has no __text, only U _NSExtensionMain.
    A WidgetKit extension should use the default main from @main/WidgetBundle.
  2. Crash in ExtensionFoundation. Without -e _NSExtensionMain the widget
    code is retained and the appex launches, but the process dies with
    EXC_BREAKPOINT (SIGTRAP) while initializing _EXRunningExtension._shared.

Environment

Host OS / version: WSL2; Windows 11 25H2 (10.0.26200), Ubuntu 26.04.1 LTS

iOS device: 27.0.1 (24A446), iPhone 15 Pro Max

Swift: 6.4 (swift-6.4-RELEASE), x86_64-unknown-linux-gnu · SDK: iphoneos27.0

xtool: 1.21.0

Steps to reproduce

  1. Run xtool dev build on a project with a WidgetKit extension (e.g. Examples/DemoExtensions).
  2. Inspect the appex binary → no __text, only U _NSExtensionMain (issue 1).
  3. In xtool/.xtool-tmp/Package.swift, drop "-Xlinker", "-e", "-Xlinker", "_NSExtensionMain", rebuild the extension product, copy it into the appex.
  4. xtool install <app>.

Expected

The extension launches and its widgets appear in the home-screen widget gallery.

Actual

The extension launches, WidgetKit resolves the bundle host, then the process traps:

  • exception.type = EXC_BREAKPOINT, signal = SIGTRAP, termination.code = 5
  • exception.codes = [1, 0x19e541268] — the same fixed address on every crash
  • faulting thread: com.apple.main-thread
closure #1 in closure #1 in ... static _EXRunningExtension._shared + 116
specialized static MainActor.assumeIsolated<A>(_:file:line:) + 140
closure #1 in closure #1 in ... static _EXRunningExtension._shared + 228
one-time initialization function for _shared + 16
_dispatch_client_callout + 16
_dispatch_once_callout + 32
static _EXRunningExtension.sharedInstance() + 112
static _EXExtension.bootstrap(with:) + 40
StudoWidgets.$main() + 40
main + 12
start + 6616

The crash is silent: a __attribute__((constructor)) that redirects
stderr/stdout into os_log arms (STUDO-STDERR armed) but captures no
message before the trap — consistent with a compiler-emitted brk #1, not a
fatalError (no _assertionFailure frames).

Evidence

  • Default appex from Examples/DemoExtensions: 49408 bytes, no __text, only U _NSExtensionMain.
  • After the entry fix: ~900 KB (debug) / ~487 KB (release), _main + __swift5_entry present.
  • chronod logs: main [WidgetBundle] → WidgetHost - Optional(ResolvedWidgetBundleHost) → crash.
  • Ruled out: Info.plist (identical to Xcode's Widget Extension template), CFBundleSupportedPlatforms/UIDeviceFamily, missing __info_plist, -all_load, debug vs release, Mach-O load commands.

Cause (issue 1)

Sources/PackLib/Packer.swift, case .appExtension:

unsafeFlags([
    // Set the entry point to Foundation`_NSExtensionMain
    "-Xlinker", "-e", "-Xlinker", "_NSExtensionMain",
    ...
]),

For SwiftUI/WidgetKit extensions the entry point must be the main generated by @main; omitting this flag keeps the widget code.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions