-
Notifications
You must be signed in to change notification settings - Fork 60
Description
Description
The flutterGetDatadogContext FFI symbol is correctly implemented in Swift (DatadogSdkPlugin.swift:20-36) with @_cdecl, but gets dead-stripped by the linker when the plugin is built as a static framework. This causes distributed tracing to silently fail in both datadog_dio and datadog_tracking_http_client.
Environment
- datadog_flutter_plugin: 3.1.0
- datadog_dio: 2.1.0
- datadog_tracking_http_client: 3.1.0
- datadog_session_replay: 1.0.0-preview.10
- Flutter: 3.32.5 / Dart: 3.8.1
- Platform: iOS (CocoaPods with
use_frameworks!)
Steps to Reproduce
- Setup Datadog SDK with
firstPartyHostsWithTracingHeadersconfigured - Use
datadog_dioordatadog_tracking_http_clientfor distributed tracing - Make an HTTP request
- Observe: trace headers (
x-datadog-trace-id,traceparent) are NOT injected
Error
When calling generateTracingContext() which calls sdk.platform.getContext() → _getDatadogContext() FFI:
Invalid argument(s): Couldn't resolve native function 'flutterGetDatadogContext'
This error is silently caught by datadog_dio's _trackRequest try-catch, making it invisible unless explicitly debugged.
Root Cause Analysis
The @ffi.Native annotation in ios_platform_bridge.dart:51-53:
@ffi.Native<_DatadogCContext Function()>(
isLeaf: true, symbol: 'flutterGetDatadogContext')
external _DatadogCContext _getDatadogContext();Has no assetId parameter and no @DefaultAsset library annotation, so Dart falls back to dlsym(RTLD_DEFAULT, "flutterGetDatadogContext") for process-level symbol lookup.
Meanwhile, the podspec sets s.static_framework = true. Combined with use_frameworks! in the Podfile, this produces a static framework. The linker extracts object files from the static archive and only includes those needed to resolve static references.
Since flutterGetDatadogContext is a module-level free C function (not an ObjC class member), the -ObjC linker flag does NOT force its inclusion. The linker dead-strips it because nothing statically references it.
Evidence:
- Symbol exists in compiled object:
nm DatadogSdkPlugin.o | grep flutterGet→T _flutterGetDatadogContext - Symbol exists in static archive:
nm Binary/datadog_flutter_plugin | grep flutterGet→T _flutterGetDatadogContext - Symbol NOT found at runtime via
dlsym(RTLD_DEFAULT, ...)→ stripped during final linking
Suggested Fix: Add assetId to the @ffi.Native annotation
@ffi.Native<_DatadogCContext Function()>(
isLeaf: true,
symbol: 'flutterGetDatadogContext',
assetId: 'datadog_flutter_plugin') // explicit asset resolution
external _DatadogCContext _getDatadogContext();Workaround
Create a custom Dio interceptor that bypasses the FFI by using TracingId.traceId() / TracingId.spanId() (pure Dart) to generate TracingContext directly, then use injectTracingHeaders() and rum.startResource() / rum.stopResource() for manual resource tracking. This avoids the getContext() FFI call entirely.
Impact
- All distributed tracing is broken (trace headers not injected)
datadog_dioanddatadog_tracking_http_clientsilently fail- HTTP resources may not be tracked depending on configuration
- Affects all iOS builds using
use_frameworks!with the defaultstatic_framework = true