Skip to content

Commit 984618b

Browse files
authored
Test sanitizers with build plans. (#2720)
The current tests for sanitizers in SwiftPM are essentially "live": they build a package that will do something to trigger a sanitizer, and then run it and confirm it fails. This is a pretty fragile way to test, and it exposes SwiftPM to a number of possible test failures that don't have anything to do with the core mission (exposing the sanitizer). This patch replaces those tests with build plan tests that validate that SwiftPM correctly invokes swiftc and clang. These tests are acceptable because for now SwiftPM doesn't have any smarts with the sanitizers: it just passes them all through to swiftc and clang. This patch also deletes the current live tests, as they are no longer necessary.
1 parent 4c25582 commit 984618b

File tree

18 files changed

+67
-234
lines changed

18 files changed

+67
-234
lines changed

Fixtures/Miscellaneous/DoubleFree/Package.swift

Lines changed: 0 additions & 18 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/Sources/exec/main.swift

Lines changed: 0 additions & 3 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/Sources/lib/lib.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/Tests/LinuxMain.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/Tests/libTests/XCTestManifests.swift

Lines changed: 0 additions & 15 deletions
This file was deleted.

Fixtures/Miscellaneous/DoubleFree/Tests/libTests/libTests.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/.gitignore

Lines changed: 0 additions & 4 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Package.swift

Lines changed: 0 additions & 18 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Sources/exec/main.swift

Lines changed: 0 additions & 3 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Sources/lib/lib.swift

Lines changed: 0 additions & 16 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Tests/LinuxMain.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Tests/libTests/XCTestManifests.swift

Lines changed: 0 additions & 15 deletions
This file was deleted.

Fixtures/Miscellaneous/ThreadRace/Tests/libTests/libTests.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,6 +2351,73 @@ final class BuildPlanTests: XCTestCase {
23512351
let dynamicLibraryPathExtension = try result.buildProduct(for: "Library").binary.extension
23522352
XCTAssertMatch(dynamicLibraryPathExtension, "dylib")
23532353
}
2354+
2355+
func testAddressSanitizer() throws {
2356+
try sanitizerTest(.address, expectedName: "address")
2357+
}
2358+
2359+
func testThreadSanitizer() throws {
2360+
try sanitizerTest(.thread, expectedName: "thread")
2361+
}
2362+
2363+
func testUndefinedSanitizer() throws {
2364+
try sanitizerTest(.undefined, expectedName: "undefined")
2365+
}
2366+
2367+
func testScudoSanitizer() throws {
2368+
try sanitizerTest(.scudo, expectedName: "scudo")
2369+
}
2370+
2371+
private func sanitizerTest(_ sanitizer: Sanitizer, expectedName: String) throws {
2372+
let fs = InMemoryFileSystem(emptyFiles:
2373+
"/Pkg/Sources/exe/main.swift",
2374+
"/Pkg/Sources/lib/lib.swift",
2375+
"/Pkg/Sources/clib/clib.c",
2376+
"/Pkg/Sources/clib/include/clib.h"
2377+
)
2378+
2379+
let diagnostics = DiagnosticsEngine()
2380+
let graph = loadPackageGraph(fs: fs, diagnostics: diagnostics,
2381+
manifests: [
2382+
Manifest.createV4Manifest(
2383+
name: "Pkg",
2384+
path: "/Pkg",
2385+
url: "/Pkg",
2386+
packageKind: .root,
2387+
targets: [
2388+
TargetDescription(name: "exe", dependencies: ["lib", "clib"]),
2389+
TargetDescription(name: "lib", dependencies: []),
2390+
TargetDescription(name: "clib", dependencies: []),
2391+
]),
2392+
]
2393+
)
2394+
XCTAssertNoDiagnostics(diagnostics)
2395+
2396+
// Unrealistic: we can't enable all of these at once on all platforms.
2397+
// This test codifies current behaviour, not ideal behaviour, and
2398+
// may need to be amended if we change it.
2399+
var parameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true)
2400+
parameters.sanitizers = EnabledSanitizers([sanitizer])
2401+
2402+
let result = BuildPlanResult(plan: try BuildPlan(
2403+
buildParameters: parameters,
2404+
graph: graph, diagnostics: diagnostics, fileSystem: fs)
2405+
)
2406+
2407+
result.checkProductsCount(1)
2408+
result.checkTargetsCount(3)
2409+
2410+
let exe = try result.target(for: "exe").swiftTarget().compileArguments()
2411+
XCTAssertTrue(exe.contains("-sanitize=\(expectedName)"))
2412+
2413+
let lib = try result.target(for: "lib").swiftTarget().compileArguments()
2414+
XCTAssertTrue(lib.contains("-sanitize=\(expectedName)"))
2415+
2416+
let clib = try result.target(for: "clib").clangTarget().basicArguments()
2417+
XCTAssertTrue(clib.contains("-fsanitize=\(expectedName)"))
2418+
2419+
XCTAssertTrue(try result.buildProduct(for: "exe").linkArguments().contains("-sanitize=\(expectedName)"))
2420+
}
23542421
}
23552422

23562423
// MARK:- Test Helpers

Tests/CommandsTests/RunToolTests.swift

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -103,52 +103,4 @@ final class RunToolTests: XCTestCase {
103103
}
104104
}
105105
}
106-
107-
// Test that thread sanitizer works.
108-
func testSanitizeThread() throws {
109-
// FIXME: We need to figure out how to test this for linux.
110-
#if os(macOS)
111-
fixture(name: "Miscellaneous/ThreadRace") { path in
112-
// Ensure that we don't abort() when we find the race. This avoids
113-
// generating the crash report on macOS.
114-
let env = ["TSAN_OPTIONS": "abort_on_error=0"]
115-
let cmdline = {
116-
try SwiftPMProduct.SwiftRun.execute(
117-
["--sanitize=thread"], packagePath: path, env: env)
118-
}
119-
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
120-
switch error {
121-
case .executionFailure(_, _, let error):
122-
XCTAssertMatch(error, .contains("ThreadSanitizer: data race"))
123-
return true
124-
default:
125-
return false
126-
}
127-
}
128-
}
129-
#endif
130-
}
131-
132-
func testSanitizeScudo() throws {
133-
// Scudo is only supported on Linux.
134-
#if os(Linux)
135-
fixture(name: "Miscellaneous/DoubleFree") { path in
136-
// Ensure that we don't abort() when we find the race. This avoids
137-
// generating the crash report on macOS.
138-
let cmdline = {
139-
try SwiftPMProduct.SwiftRun.execute(
140-
["--sanitize=scudo"], packagePath: path)
141-
}
142-
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
143-
switch error {
144-
case .executionFailure(_, _, let error):
145-
XCTAssertMatch(error, .contains("invalid chunk state"))
146-
return true
147-
default:
148-
return false
149-
}
150-
}
151-
}
152-
#endif
153-
}
154106
}

Tests/CommandsTests/TestToolTests.swift

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,6 @@ final class TestToolTests: XCTestCase {
3030
XCTAssert(try execute(["--version"]).stdout.contains("Swift Package Manager"))
3131
}
3232

33-
// Test that thread sanitizer works.
34-
func testSanitizeThread() throws {
35-
// FIXME: We need to figure out how to test this for linux.
36-
// Disabled because of https://bugs.swift.org/browse/SR-7272
37-
#if false
38-
fixture(name: "Miscellaneous/ThreadRace") { path in
39-
// Ensure that we don't abort() when we find the race. This avoids
40-
// generating the crash report on macOS.
41-
let env = ["TSAN_OPTIONS": "abort_on_error=0"]
42-
let cmdline = {
43-
try SwiftPMProduct.SwiftTest.execute(
44-
["--sanitize=thread"], packagePath: path, env: env)
45-
}
46-
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
47-
switch error {
48-
case .executionFailure(_, _, let error):
49-
XCTAssertMatch(error, .contains("ThreadSanitizer: data race"))
50-
return true
51-
default:
52-
return false
53-
}
54-
}
55-
}
56-
#endif
57-
}
58-
5933
func testNumWorkersParallelRequeriment() throws {
6034
// Running swift-test fixtures on linux is not yet possible.
6135
#if os(macOS)
@@ -80,25 +54,4 @@ final class TestToolTests: XCTestCase {
8054
}
8155
#endif
8256
}
83-
84-
func testSanitizeScudo() throws {
85-
// This test only runs on Linux because Scudo only runs on Linux
86-
#if os(Linux)
87-
fixture(name: "Miscellaneous/DoubleFree") { path in
88-
let cmdline = {
89-
try SwiftPMProduct.SwiftTest.execute(
90-
["--sanitize=scudo"], packagePath: path)
91-
}
92-
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
93-
switch error {
94-
case .executionFailure(_, _, let error):
95-
XCTAssertMatch(error, .contains("invalid chunk state"))
96-
return true
97-
default:
98-
return false
99-
}
100-
}
101-
}
102-
#endif
103-
}
10457
}

0 commit comments

Comments
 (0)