Skip to content

Commit 5e61e57

Browse files
committed
SwiftBuild Integration: Enable some sanitizers
Update the SwiftPM's SwiftBuild integration to support enabling `address`, `thread` and `undefined` sanitizers while erroring out on the `scudo` and `fuzzer`. Depends on: swiftlang/swift-build#926
1 parent 1265093 commit 5e61e57

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,20 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
891891
}
892892
}
893893

894+
for sanitizer in buildParameters.sanitizers.sanitizers {
895+
self.observabilityScope.emit(debug:"Enabling \(sanitizer) sanitizer")
896+
switch sanitizer {
897+
case .address:
898+
settings["ENABLE_ADDRESS_SANITIZER"] = "YES"
899+
case .thread:
900+
settings["ENABLE_THREAD_SANITIZER"] = "YES"
901+
case .undefined:
902+
settings["ENABLE_UNDEFINED_BEHAVIOR_SANITIZER"] = "YES"
903+
case .fuzzer, .scudo:
904+
throw StringError("\(sanitizer) is not currently supported with this build system.")
905+
}
906+
}
907+
894908
// FIXME: workaround for old Xcode installations such as what is in CI
895909
settings["LM_SKIP_METADATA_EXTRACTION"] = "YES"
896910
if let symbolGraphOptions {

Sources/_InternalTestSupport/MockBuildTestHelper.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ public func mockBuildParameters(
9292
linkTimeOptimizationMode: BuildParameters.LinkTimeOptimizationMode? = nil,
9393
omitFramePointers: Bool? = nil,
9494
enableXCFrameworksOnLinux: Bool = false,
95-
prepareForIndexing: BuildParameters.PrepareForIndexingMode = .off
95+
prepareForIndexing: BuildParameters.PrepareForIndexingMode = .off,
96+
sanitizers: [Sanitizer] = [],
9697
) -> BuildParameters {
9798
try! BuildParameters(
9899
destination: destination,
@@ -104,6 +105,7 @@ public func mockBuildParameters(
104105
buildSystemKind: buildSystemKind,
105106
pkgConfigDirectories: [],
106107
workers: 3,
108+
sanitizers: EnabledSanitizers(Set(sanitizers)),
107109
indexStoreMode: indexStoreMode,
108110
prepareForIndexing: prepareForIndexing,
109111
enableXCFrameworksOnLinux: enableXCFrameworksOnLinux,
@@ -120,7 +122,7 @@ public func mockBuildParameters(
120122
linkTimeOptimizationMode: linkTimeOptimizationMode,
121123
shouldDisableLocalRpath: shouldDisableLocalRpath,
122124
shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib
123-
)
125+
),
124126
)
125127
}
126128

Sources/_InternalTestSupport/SwiftTesting+Tags.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ extension Tag.Platform {
2828
@Tag public static var FileSystem: Tag
2929
}
3030

31+
extension Tag.FunctionalArea {
32+
@Tag public static var PIF: Tag
33+
@Tag public static var IndexMode: Tag
34+
@Tag public static var Sanitizer: Tag
35+
}
36+
3137
extension Tag.Feature {
3238
public enum Command {}
3339
public enum CommandLineArguments {}
@@ -192,8 +198,3 @@ extension Tag.Feature.Product {
192198
@Tag public static var Execute: Tag
193199
@Tag public static var Link: Tag
194200
}
195-
196-
extension Tag.FunctionalArea {
197-
@Tag public static var PIF: Tag
198-
@Tag public static var IndexMode: Tag
199-
}

Tests/CommandsTests/Sanitizer+ExtensionsTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import enum PackageModel.Sanitizer
1515

1616
@Suite(
1717
.tags(
18-
Tag.TestSize.small,
18+
.TestSize.small,
19+
.FunctionalArea.Sanitizer,
1920
),
2021
)
2122
struct SanitizerExtensionTests {

Tests/SwiftBuildSupportTests/SwiftBuildSystemTests.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,90 @@ func withInstantiatedSwiftBuildSystem(
113113
}
114114
}
115115

116+
extension PackageModel.Sanitizer {
117+
var hasSwiftBuildSupport: Bool {
118+
switch self {
119+
case .address, .thread, .undefined: true
120+
case .fuzzer, .scudo: false
121+
}
122+
}
123+
124+
var swiftBuildSettingName: String? {
125+
switch self {
126+
case .address: "ENABLE_ADDRESS_SANITIZER"
127+
case .thread: "ENABLE_THREAD_SANITIZER"
128+
case .undefined: "ENABLE_UNDEFINED_BEHAVIOR_SANITIZER"
129+
case .fuzzer, .scudo: nil
130+
}
131+
132+
}
133+
}
134+
116135
@Suite(
117136
.tags(
118137
.TestSize.medium,
119138
),
120139
)
121140
struct SwiftBuildSystemTests {
122141

142+
@Suite(
143+
.tags(
144+
.FunctionalArea.Sanitizer,
145+
)
146+
)
147+
struct SanitizerTests {
148+
149+
@Test(
150+
arguments: PackageModel.Sanitizer.allCases.filter { $0.hasSwiftBuildSupport },
151+
)
152+
func sanitizersSettingSetCorrectBuildRequest(
153+
sanitizer: Sanitizer,
154+
) async throws {
155+
try await withInstantiatedSwiftBuildSystem(
156+
fromFixture: "PIFBuilder/Simple",
157+
buildParameters: mockBuildParameters(
158+
destination: .host,
159+
sanitizers: [sanitizer],
160+
),
161+
) { swiftBuild, session, observabilityScope, buildParameters in
162+
let buildSettings: SWBBuildParameters = try await swiftBuild.makeBuildParameters(
163+
session: session,
164+
symbolGraphOptions: nil,
165+
setToolchainSetting: false, // Set this to false as SwiftBuild checks the toolchain path
166+
)
167+
168+
let synthesizedArgs = try #require(buildSettings.overrides.synthesized)
169+
170+
let swbSettingName = try #require(sanitizer.swiftBuildSettingName)
171+
#expect(synthesizedArgs.table[swbSettingName] == "YES")
172+
}
173+
174+
}
175+
176+
@Test(
177+
arguments: PackageModel.Sanitizer.allCases.filter { !$0.hasSwiftBuildSupport },
178+
)
179+
func unsupportedSanitizersRaisesError(
180+
sanitizer: Sanitizer,
181+
) async throws {
182+
try await withInstantiatedSwiftBuildSystem(
183+
fromFixture: "PIFBuilder/Simple",
184+
buildParameters: mockBuildParameters(
185+
destination: .host,
186+
sanitizers: [sanitizer],
187+
),
188+
) { swiftBuild, session, observabilityScope, buildParameters in
189+
await #expect(throws: (any Error).self) {
190+
try await swiftBuild.makeBuildParameters(
191+
session: session,
192+
symbolGraphOptions: nil,
193+
setToolchainSetting: false, // Set this to false as SwiftBuild checks the toolchain path
194+
)
195+
}
196+
}
197+
}
198+
}
199+
123200
@Test(
124201
arguments: BuildParameters.IndexStoreMode.allCases,
125202
// arguments: [BuildParameters.IndexStoreMode.on],

0 commit comments

Comments
 (0)