Skip to content

Commit 20b120d

Browse files
vlmaciidgh
authored andcommitted
Add thread sanitizer support
1 parent b66765f commit 20b120d

File tree

17 files changed

+336
-16
lines changed

17 files changed

+336
-16
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// swift-tools-version:4.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "race",
7+
targets: [
8+
.target(
9+
name: "lib",
10+
dependencies: []),
11+
.target(
12+
name: "exec",
13+
dependencies: ["lib"]),
14+
.testTarget(
15+
name: "libTests",
16+
dependencies: ["lib"]),
17+
]
18+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# race
2+
3+
A description of this package.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import lib
2+
3+
executeRace()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Dispatch
2+
3+
public func executeRace() {
4+
var global = 5
5+
6+
let sema = DispatchSemaphore(value: 0)
7+
DispatchQueue.global().async {
8+
global = 6
9+
sema.signal()
10+
}
11+
12+
global = 7
13+
sema.wait()
14+
15+
print(global)
16+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
3+
import libTests
4+
5+
var tests = [XCTestCaseEntry]()
6+
tests += libTests.__allTests()
7+
8+
XCTMain(tests)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import XCTest
2+
3+
extension libTests {
4+
static let __allTests = [
5+
("testRace", testRace),
6+
]
7+
}
8+
9+
#if !os(macOS)
10+
public func __allTests() -> [XCTestCaseEntry] {
11+
return [
12+
testCase(libTests.__allTests),
13+
]
14+
}
15+
#endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
import lib
3+
4+
final class libTests: XCTestCase {
5+
func testRace() {
6+
executeRace()
7+
}
8+
}

Sources/Build/BuildPlan.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ public struct BuildParameters {
7272
/// If should link the Swift stdlib statically.
7373
public let shouldLinkStaticSwiftStdlib: Bool
7474

75+
/// Which compiler sanitizers should be enabled
76+
public let sanitizers: EnabledSanitizers
77+
7578
/// If should enable llbuild manifest caching.
7679
public let shouldEnableManifestCaching: Bool
7780

@@ -99,7 +102,8 @@ public struct BuildParameters {
99102
flags: BuildFlags,
100103
toolsVersion: ToolsVersion = ToolsVersion.currentToolsVersion,
101104
shouldLinkStaticSwiftStdlib: Bool = false,
102-
shouldEnableManifestCaching: Bool = false
105+
shouldEnableManifestCaching: Bool = false,
106+
sanitizers: EnabledSanitizers = EnabledSanitizers()
103107
) {
104108
self.dataPath = dataPath
105109
self.configuration = configuration
@@ -109,6 +113,7 @@ public struct BuildParameters {
109113
self.toolsVersion = toolsVersion
110114
self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib
111115
self.shouldEnableManifestCaching = shouldEnableManifestCaching
116+
self.sanitizers = sanitizers
112117
}
113118
}
114119

@@ -210,6 +215,7 @@ public final class ClangTargetDescription {
210215
args += ["-I", clangTarget.includeDir.asString]
211216
args += additionalFlags
212217
args += moduleCacheArgs
218+
args += buildParameters.sanitizers.compileCFlags()
213219

214220
// User arguments (from -Xcc and -Xcxx below) should follow generated arguments to allow user overrides
215221
args += buildParameters.flags.cCompilerFlags
@@ -323,6 +329,7 @@ public final class SwiftTargetDescription {
323329
args += activeCompilationConditions
324330
args += additionalFlags
325331
args += moduleCacheArgs
332+
args += buildParameters.sanitizers.compileSwiftFlags()
326333

327334
// Add arguments to colorize output if stdout is tty
328335
if buildParameters.isTTY {
@@ -434,6 +441,7 @@ public final class ProductBuildDescription {
434441
public func linkArguments() -> [String] {
435442
var args = [buildParameters.toolchain.swiftCompiler.asString]
436443
args += buildParameters.toolchain.extraSwiftCFlags
444+
args += buildParameters.sanitizers.linkSwiftFlags()
437445
args += additionalFlags
438446

439447
if buildParameters.configuration == .debug {

Sources/Build/Sanitizers.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2018 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Basic
12+
import Utility
13+
14+
/// Available runtime sanitizers.
15+
public enum Sanitizer: String {
16+
case address
17+
case thread
18+
19+
/// Return an established short name for a sanitizer, e.g. "asan".
20+
public var shortName: String {
21+
switch self {
22+
case .address: return "asan"
23+
case .thread: return "tsan"
24+
}
25+
}
26+
}
27+
28+
/// A set of enabled runtime sanitizers.
29+
public struct EnabledSanitizers {
30+
/// A set of enabled sanitizers.
31+
public let sanitizers: Set<Sanitizer>
32+
33+
public init(_ sanitizers: Set<Sanitizer> = []) {
34+
// FIXME: We need to throw from here if given sanitizers can't be
35+
// enabled. For e.g., it is illegal to enable thread and address
36+
// sanitizers together.
37+
self.sanitizers = sanitizers
38+
}
39+
40+
/// Sanitization flags for the C family compiler (C/C++).
41+
public func compileCFlags() -> [String] {
42+
return sanitizers.map({ "-fsanitize=\($0.rawValue)" })
43+
}
44+
45+
/// Sanitization flags for the Swift compiler.
46+
public func compileSwiftFlags() -> [String] {
47+
return sanitizers.map({ "-sanitize=\($0.rawValue)" })
48+
}
49+
50+
/// Sanitization flags for the Swift linker and compiler are the same so far.
51+
public func linkSwiftFlags() -> [String] {
52+
return compileSwiftFlags()
53+
}
54+
55+
public var isEmpty: Bool {
56+
return sanitizers.isEmpty
57+
}
58+
}
59+
60+
extension Sanitizer: StringEnumArgument {
61+
public static let completion: ShellCompletion = .values([
62+
(address.rawValue, "enable Address sanitizer"),
63+
(thread.rawValue, "enable Thread sanitizer"),
64+
])
65+
}

Sources/Commands/Options.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,8 @@ public class ToolOptions {
5252
/// Skip updating dependencies from their remote during a resolution.
5353
public var skipDependencyUpdate = false
5454

55+
/// Which compile-time sanitizers should be enabled.
56+
public var sanitizers = EnabledSanitizers()
57+
5558
public required init() {}
5659
}

0 commit comments

Comments
 (0)