Skip to content

Commit 31f762e

Browse files
authored
Merge pull request #2016 from DanBlackwell/add-memtagstack-option
[Sanitizers] Add support for -sanitize=memtag-stack
2 parents bfcec90 + f474ff0 commit 31f762e

File tree

9 files changed

+71
-19
lines changed

9 files changed

+71
-19
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,12 +2754,17 @@ extension Driver {
27542754
// Support is determined by existence of the sanitizer library.
27552755
// FIXME: Should we do this? This prevents cross-compiling with sanitizers
27562756
// enabled.
2757-
var sanitizerSupported = try toolchain.runtimeLibraryExists(
2758-
for: stableAbi ? .address_stable_abi : sanitizer,
2759-
targetInfo: targetInfo,
2760-
parsedOptions: &parsedOptions,
2761-
isShared: sanitizer != .fuzzer && !stableAbi
2762-
)
2757+
var sanitizerSupported = true
2758+
2759+
// memtag-stack sanitizer doesn't have a runtime library
2760+
if sanitizer.hasRuntimeLibrary {
2761+
sanitizerSupported = try toolchain.runtimeLibraryExists(
2762+
for: stableAbi ? .address_stable_abi : sanitizer,
2763+
targetInfo: targetInfo,
2764+
parsedOptions: &parsedOptions,
2765+
isShared: sanitizer != .fuzzer && !stableAbi
2766+
)
2767+
}
27632768

27642769
if sanitizer == .thread {
27652770
// TSAN is unavailable on Windows
@@ -2813,6 +2818,16 @@ extension Driver {
28132818
)
28142819
}
28152820

2821+
// Address and memtag-stack sanitizers can not be enabled concurrently.
2822+
if set.contains(.memtag_stack) && set.contains(.address) {
2823+
diagnosticEngine.emit(
2824+
.error_argument_not_allowed_with(
2825+
arg: "-sanitize=memtag-stack",
2826+
other: "-sanitize=address"
2827+
)
2828+
)
2829+
}
2830+
28162831
// Scudo can only be run with ubsan.
28172832
if set.contains(.scudo) {
28182833
let allowedSanitizers: Set<Sanitizer> = [.scudo, .undefinedBehavior]

Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,22 @@ extension Toolchain {
6565
return result
6666
}
6767

68+
/// Returns true if a runtime library exists for this sanitizer. Note: some
69+
/// sanitizers don't have runtime libraries - ideally this function should
70+
/// not be called on them - first check with `sanitizer.hasRuntimeLibrary`
6871
func runtimeLibraryExists(
6972
for sanitizer: Sanitizer,
7073
targetInfo: FrontendTargetInfo,
7174
parsedOptions: inout ParsedOptions,
7275
isShared: Bool
7376
) throws -> Bool {
74-
let runtimeName = try runtimeLibraryName(
77+
guard let runtimeName = try runtimeLibraryName(
7578
for: sanitizer,
7679
targetTriple: targetInfo.target.triple,
7780
isShared: isShared
78-
)
81+
) else {
82+
return false
83+
}
7984
let path = try clangLibraryPath(
8085
for: targetInfo,
8186
parsedOptions: &parsedOptions

Sources/SwiftDriver/Toolchains/DarwinToolchain.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,12 @@ public final class DarwinToolchain: Toolchain {
168168
for sanitizer: Sanitizer,
169169
targetTriple: Triple,
170170
isShared: Bool
171-
) throws -> String {
171+
) throws -> String? {
172+
guard let libraryName = sanitizer.runtimeLibraryName else {
173+
return nil
174+
}
172175
return """
173-
libclang_rt.\(sanitizer.libraryName)_\
176+
libclang_rt.\(libraryName)_\
174177
\(targetTriple.darwinPlatform!.libraryNameSuffix)\
175178
\(isShared ? "_dynamic.dylib" : ".a")
176179
"""

Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,12 @@ public final class GenericUnixToolchain: Toolchain {
148148
for sanitizer: Sanitizer,
149149
targetTriple: Triple,
150150
isShared: Bool
151-
) throws -> String {
151+
) throws -> String? {
152+
guard let runtimeLibraryName = sanitizer.runtimeLibraryName else {
153+
return nil
154+
}
152155
let environment = (targetTriple.environment == .android) ? "-android" : ""
153-
return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName)\(environment).a"
156+
return "libclang_rt.\(runtimeLibraryName)-\(targetTriple.archName)\(environment).a"
154157
}
155158

156159
public func addPlatformSpecificCommonFrontendOptions(

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,12 @@ public protocol Toolchain {
143143
targetInfo: FrontendTargetInfo
144144
) throws -> ResolvedTool
145145

146+
/// Returns the runtime library name for a given sanitizer (or nil if the sanitizer does not have a runtime library)
146147
func runtimeLibraryName(
147148
for sanitizer: Sanitizer,
148149
targetTriple: Triple,
149150
isShared: Bool
150-
) throws -> String
151+
) throws -> String?
151152

152153
func platformSpecificInterpreterEnvironmentVariables(
153154
env: ProcessEnvironmentBlock,

Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ public final class WebAssemblyToolchain: Toolchain {
146146
for sanitizer: Sanitizer,
147147
targetTriple: Triple,
148148
isShared: Bool
149-
) throws -> String {
149+
) throws -> String? {
150150
switch sanitizer {
151151
case .address:
152-
return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName).a"
152+
return "libclang_rt.\(sanitizer.runtimeLibraryName!)-\(targetTriple.archName).a"
153153
default:
154154
throw Error.sanitizersUnsupportedForTarget(targetTriple.triple)
155155
}

Sources/SwiftDriver/Toolchains/WindowsToolchain.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,17 @@ extension WindowsToolchain.ToolchainValidationError {
135135
public var globalDebugPathRemapping: String? { nil }
136136

137137
public func runtimeLibraryName(for sanitizer: Sanitizer, targetTriple: Triple,
138-
isShared: Bool) throws -> String {
138+
isShared: Bool) throws -> String? {
139139
// TODO(compnerd) handle shared linking
140140

141141
// FIXME(compnerd) when should `clang_rt.ubsan_standalone_cxx` be used?
142142
if sanitizer == .undefinedBehavior {
143143
return "clang_rt.ubsan_standalone.lib"
144144
}
145-
return "clang_rt.\(sanitizer.libraryName).lib"
145+
if sanitizer == .memtag_stack {
146+
throw ToolchainValidationError.unsupportedSanitizer(sanitizer)
147+
}
148+
return "clang_rt.\(sanitizer.runtimeLibraryName!).lib"
146149
}
147150

148151
public func validateArgs(_ parsedOptions: inout ParsedOptions,

Sources/SwiftDriver/Utilities/Sanitizer.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,27 @@ public enum Sanitizer: String, Hashable {
3333
/// Scudo hardened allocator
3434
case scudo
3535

36-
/// The name inside the `compiler_rt` library path (e.g. libclang_rt.{name}.a)
37-
var libraryName: String {
36+
/// Memory-Tagging-based stack sanitizer
37+
case memtag_stack = "memtag-stack"
38+
39+
/// Does this sanitizer have a runtime library
40+
var hasRuntimeLibrary: Bool {
41+
if self == .memtag_stack {
42+
return false
43+
}
44+
return true
45+
}
46+
47+
/// The name inside the `compiler_rt` runtime library path (e.g. libclang_rt.{name}.a)
48+
var runtimeLibraryName: String? {
3849
switch self {
3950
case .address: return "asan"
4051
case .address_stable_abi: return "asan_abi"
4152
case .thread: return "tsan"
4253
case .undefinedBehavior: return "ubsan"
4354
case .fuzzer: return "fuzzer"
4455
case .scudo: return "scudo"
56+
case .memtag_stack: return nil
4557
}
4658
}
4759
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,16 @@ final class SwiftDriverTests: XCTestCase {
31273127
XCTAssertJobInvocationMatches(jobs[2], .flag("-fsanitize=undefined"))
31283128
}
31293129

3130+
do {
3131+
// memory tagging stack sanitizer
3132+
var driver = try Driver(args: commonArgs + ["-sanitize=memtag-stack"])
3133+
let jobs = try driver.planBuild().removingAutolinkExtractJobs()
3134+
3135+
XCTAssertEqual(jobs.count, 3)
3136+
XCTAssertJobInvocationMatches(jobs[0], .flag("-sanitize=memtag-stack"))
3137+
// No runtime for memtag-stack - thus no linker arg required
3138+
}
3139+
31303140
// FIXME: This test will fail when run on macOS, because the driver uses
31313141
// the existence of the runtime support libraries to determine if
31323142
// a sanitizer is supported. Until we allow cross-compiling with

0 commit comments

Comments
 (0)