Skip to content

Commit 07592fe

Browse files
ypopovychclaude
andcommitted
Hide bundled dependency symbols to prevent OpenTelemetry type clashes
The framework statically links OpenTelemetry (api/sdk), KSCrash, Kronos, SigmaSwiftStatistics and swift-code-coverage and exported all of their symbols. When a project-under-test links its own copy of the same dependency (e.g. opentelemetry-swift at a different version), dyld coalesces the duplicate weak type-metadata symbols to a single process-wide definition. Mismatched layouts then make one image read objects through the other's metadata, crashing in swift_getObjectType (observed via OpenTelemetryContextProvider.setActiveSpan). Mark every bundled-dependency symbol non-exported via UNEXPORTED_SYMBOLS_FILE so each image binds its own copy and dyld can't coalesce them. Only the public DatadogSDKTesting API stays exported (762 symbols vs ~11,240 before). Also drop DDInstrumentationControl.openTelemetryTracer and its README section: with OpenTelemetry now fully private, the documented `as? Tracer` interop can no longer work, so the hook is removed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
1 parent 3dd5144 commit 07592fe

4 files changed

Lines changed: 61 additions & 20 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Symbols to hide (make local / private_extern) in DatadogSDKTesting.framework.
2+
#
3+
# WHY: every dependency we statically link into the framework exports its
4+
# symbols by default. When a project-under-test links its OWN copy of the same
5+
# dependency (e.g. opentelemetry-swift), dyld coalesces the duplicate weak
6+
# type-metadata symbols to a single definition process-wide. If the two copies
7+
# differ in version/layout, one image ends up reading objects through the
8+
# other's metadata -> `swift_getObjectType` walks a bad pointer -> SEGV_ACCERR.
9+
# Marking these symbols non-exported stops dyld from coalescing them: each image
10+
# binds to its own copy. Only the public DatadogSDKTesting API stays exported.
11+
#
12+
# Passed to ld64 via `-unexported_symbols_list` (see UNEXPORTED_SYMBOLS_FILE /
13+
# OTHER_LDFLAGS on the framework target). Patterns use fnmatch globs and are
14+
# matched against the full mangled symbol name (leading underscore included).
15+
#
16+
# CAVEAT: this only prevents dyld symbol coalescing. It does NOT change the
17+
# mangled names, so name-keyed Swift runtime lookups (dynamic casts, Codable,
18+
# NSClassFromString) can still cross images in rare cases. For a hard guarantee
19+
# use module renaming instead. See the OpenTelemetry-isolation discussion.
20+
#
21+
# NOTE: Swift mangles the module name as a length-prefixed component
22+
# (e.g. `16OpenTelemetryApi`, 16 == strlen). It appears not only at the start of
23+
# symbols the module DEFINES but also mid-string in every symbol that REFERENCES
24+
# one of its types, so the globs are intentionally unanchored (`*...*`).
25+
# Keying on the length prefix keeps us from clobbering our own identifiers such
26+
# as `OpenTelemetryContextProvider` (mangled `28OpenTelemetry...`).
27+
28+
# --- opentelemetry-swift-core ---
29+
*16OpenTelemetryApi*
30+
*16OpenTelemetrySdk*
31+
32+
# --- swift-code-coverage ---
33+
*12CodeCoverage*
34+
*21CodeCoverageCollector*
35+
*18CodeCoverageParser*
36+
37+
# --- Kronos ---
38+
*6Kronos*
39+
40+
# --- SigmaSwiftStatistics ---
41+
*20SigmaSwiftStatistics*
42+
43+
# --- EventsExporter (internal SDK module, not part of the public product) ---
44+
*14EventsExporter*
45+
46+
# --- KSCrash (C/ObjC + Swift) ---
47+
# Modules: KSCrashRecording / RecordingCore / RecordingCoreSwift / ReportingCore
48+
# / Core / Filters / Sinks / Installations / DemangleFilter / etc.
49+
# NOTE: hiding C/ObjC symbols stops the linker-level duplicate, but the ObjC
50+
# runtime still registers classes by name and KSCrash installs process-wide
51+
# signal/exception handlers; if a project-under-test also links KSCrash that
52+
# handler-install conflict is a separate concern this list does NOT solve.
53+
# All KSCrash C functions are namespaced under `ks` (`_ksobjc_`, `_kscm_`,
54+
# `_ksjson_`, `_kscrash_`, ...); inline log wrappers are under `_i_ks`.
55+
*KSCrash*
56+
_ks*
57+
_i_ks*
58+
_OBJC_CLASS_$_KS*
59+
_OBJC_METACLASS_$_KS*

DatadogSDKTesting.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,6 +2775,7 @@
27752775
SUPPORTS_MACCATALYST = YES;
27762776
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
27772777
SWIFT_EMIT_LOC_STRINGS = YES;
2778+
UNEXPORTED_SYMBOLS_FILE = "$(SRCROOT)/DatadogSDKTesting-unexported-symbols.txt";
27782779
};
27792780
name = Debug;
27802781
};
@@ -2816,6 +2817,7 @@
28162817
SUPPORTS_MACCATALYST = YES;
28172818
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
28182819
SWIFT_EMIT_LOC_STRINGS = YES;
2820+
UNEXPORTED_SYMBOLS_FILE = "$(SRCROOT)/DatadogSDKTesting-unexported-symbols.txt";
28192821
};
28202822
name = Release;
28212823
};

README.md

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,6 @@ You can add custom tags inside your test methods. The static property `DDTest.cu
108108
DDTest.current!.setTag(key: "key1", value: "value1")
109109
```
110110

111-
## Using OpenTelemetry (only for Swift)
112-
113-
The Datadog Swift testing framework uses [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-swift) as the tracing technology under the hood. You can access the OpenTelemetry tracer using `DDInstrumentationControl.openTelemetryTracer` and can use any OpenTelemetry api. For example, for adding a tag/attribute:
114-
115-
```swift
116-
import DatadogSDKTesting
117-
import OpenTelemetryApi
118-
119-
let tracer = DDInstrumentationControl.openTelemetryTracer as? Tracer
120-
let span = tracer?.spanBuilder(spanName: "ChildSpan").startSpan()
121-
span?.setAttribute(key: "OTTag2", value: "OTValue2")
122-
span?.end()
123-
```
124-
125-
The test target needs to link explicitly with `opentelemetry-swift`.
126-
127111
## Using Info.plist for configuration
128112

129113
Alternatively to setting environment variables, all configuration values can be provided by adding them to the `Info.plist` file of the Test bundle (not the App bundle). If the same setting is set both in an environment variable and in the `Info.plist` file, the environment variable takes precedence.

Sources/DatadogSDKTesting/DDInstrumentationControl.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,4 @@ public class DDInstrumentationControl: NSObject {
4040
@objc public static func stopStderrCapture() {
4141
DDTestMonitor.instance?.stopStderrCapture()
4242
}
43-
44-
public static var openTelemetryTracer: AnyObject? {
45-
return DDTestMonitor.instance?.tracer.tracerSdk
46-
}
4743
}

0 commit comments

Comments
 (0)