Skip to content

Crash (EXC_BREAKPOINT) in DeviceAccessManager.advertisingIdentifier() when ASIdentifierManager returns nil #1273

Description

@jstamatova

Describe the bug

DeviceAccessManager.advertisingIdentifier() force-bridges ASIdentifierManager.shared().advertisingIdentifier into a non-optional Swift UUID:

// PrebidMobile/Swift/PrebidMobileRendering/Utilities/DeviceAccessManager.swift:85
@objc public func advertisingIdentifier() -> String {
    ASIdentifierManager.shared().advertisingIdentifier.uuidString
}

Apple annotates -[ASIdentifierManager advertisingIdentifier] as nonnull, so it bridges to a non-optional UUID in Swift. But in rare device states the ObjC property returns nil (the identifier is fetched over XPC from a system daemon that can be unavailable — e.g. very early in launch before the AdSupport service is ready, just after boot / before first unlock, under memory pressure / XPC failure, or under certain MDM / Screen Time restrictions). When it returns nil, the implicit NSUUID? -> UUID bridge calls UUID._unconditionallyBridgeFromObjectiveC, which traps -> EXC_BREAKPOINT and the app crashes.

Note: normal ATT denial / notDetermined does NOT cause this — that returns the all-zeros UUID (00000000-0000-0000-0000-000000000000), which bridges fine. The crash is specifically the nil case, where the OS returns nil despite the nonnull annotation.

This is hit whenever a bid request is built with Targeting.shared.isAllowedAccessDeviceData == true (PBMDeviceInfoParameterBuilder.m:88 reads deviceAccessManager.advertisingIdentifier), so any fetchDemand() call can crash.

To Reproduce
Steps to reproduce the behavior:

  1. Force ASIdentifierManager.shared().advertisingIdentifier to return nil (e.g. swizzle the getter for testing).
  2. Ensure Targeting.shared.isAllowedAccessDeviceData returns true.
  3. Trigger a bid request via BannerAdUnit.fetchDemand(...).
  4. See error - app crashes with EXC_BREAKPOINT in DeviceAccessManager.advertisingIdentifier() at DeviceAccessManager.swift:85.

Expected behavior

The SDK should tolerate a nil advertising identifier (fall back to an empty string / omit the ifa param) instead of trapping. Suggested fix - treat the value as optional:

@objc public func advertisingIdentifier() -> String {
    ASIdentifierManager.shared().advertisingIdentifier?.uuidString ?? ""
}

Screenshots

Symbolicated crash stack (abridged):

Crashed: com.apple.main-thread
0  Foundation      UUID._unconditionallyBridgeFromObjectiveC + 196
1  PrebidMobile    DeviceAccessManager.advertisingIdentifier()  (DeviceAccessManager.swift:85)
2  PrebidMobile    -[PBMDeviceInfoParameterBuilder buildBidRequest:]  (PBMDeviceInfoParameterBuilder.m:88)
3  PrebidMobile    +[PBMParameterBuilderService buildParamsDictWithAdConfiguration:...]
5  PrebidMobile    -[PBMBidRequester_Objc getRTBRequest]  (PBMBidRequester.m:180)
6  PrebidMobile    -[PBMBidRequester_Objc makeRequestWithCompletion:]  (PBMBidRequester.m:75)
9  PrebidMobile    UserAgentService.fetchUserAgent(completion:)  (UserAgentService.swift:37)
11 PrebidMobile    -[PBMBidRequester_Objc requestBidsWithCompletion:]  (PBMBidRequester.m:55)
12 PrebidMobile    AdUnit.baseFetchDemand(adObject:completion:)  (AdUnit.swift:182)
13 PrebidMobile    AdUnit.fetchDemand(completionBidInfo:)  (AdUnit.swift:113)
14 <app>           BannerAdUnit.fetchDemand { ... }

Desktop (please complete the following information):

  • OS: N/A (iOS SDK issue, not desktop)
  • Browser: N/A
  • Version: N/A

Smartphone (please complete the following information):

  • Device: Multiple (47 distinct devices affected in production)
  • OS: iOS (observed on iOS 18.7)
  • Browser: N/A (native app, in-app ad rendering)
  • Version: PrebidMobile 3.3.1 (same unguarded code also present on master)

Additional context

Low but persistent volume in our production Crashlytics - 50 occurrences across 47 devices (0.6% of crashing users). The root cause is entirely inside the SDK: apps cannot prevent ASIdentifierManager from returning nil (it comes from a system daemon being momentarily unavailable), so this can only be fixed upstream by making the bridge nil-safe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions