Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2754,12 +2754,17 @@ extension Driver {
// Support is determined by existence of the sanitizer library.
// FIXME: Should we do this? This prevents cross-compiling with sanitizers
// enabled.
var sanitizerSupported = try toolchain.runtimeLibraryExists(
for: stableAbi ? .address_stable_abi : sanitizer,
targetInfo: targetInfo,
parsedOptions: &parsedOptions,
isShared: sanitizer != .fuzzer && !stableAbi
)
var sanitizerSupported = true

// memtag-stack sanitizer doesn't have a runtime library
if sanitizer.hasRuntimeLibrary {
sanitizerSupported = try toolchain.runtimeLibraryExists(
for: stableAbi ? .address_stable_abi : sanitizer,
targetInfo: targetInfo,
parsedOptions: &parsedOptions,
isShared: sanitizer != .fuzzer && !stableAbi
)
}

if sanitizer == .thread {
// TSAN is unavailable on Windows
Expand Down Expand Up @@ -2813,6 +2818,16 @@ extension Driver {
)
}

// Address and memtag-stack sanitizers can not be enabled concurrently.
if set.contains(.memtag_stack) && set.contains(.address) {
diagnosticEngine.emit(
.error_argument_not_allowed_with(
arg: "-sanitize=memtag-stack",
other: "-sanitize=address"
)
)
}

// Scudo can only be run with ubsan.
if set.contains(.scudo) {
let allowedSanitizers: Set<Sanitizer> = [.scudo, .undefinedBehavior]
Expand Down
9 changes: 7 additions & 2 deletions Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,22 @@ extension Toolchain {
return result
}

/// Returns true if a runtime library exists for this sanitizer. Note: some
/// sanitizers don't have runtime libraries - ideally this function should
/// not be called on them - first check with `sanitizer.hasRuntimeLibrary`
func runtimeLibraryExists(
for sanitizer: Sanitizer,
targetInfo: FrontendTargetInfo,
parsedOptions: inout ParsedOptions,
isShared: Bool
) throws -> Bool {
let runtimeName = try runtimeLibraryName(
guard let runtimeName = try runtimeLibraryName(
for: sanitizer,
targetTriple: targetInfo.target.triple,
isShared: isShared
)
) else {
return false
}
let path = try clangLibraryPath(
for: targetInfo,
parsedOptions: &parsedOptions
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftDriver/Toolchains/DarwinToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,12 @@ public final class DarwinToolchain: Toolchain {
for sanitizer: Sanitizer,
targetTriple: Triple,
isShared: Bool
) throws -> String {
) throws -> String? {
guard let libraryName = sanitizer.runtimeLibraryName else {
return nil
}
return """
libclang_rt.\(sanitizer.libraryName)_\
libclang_rt.\(libraryName)_\
\(targetTriple.darwinPlatform!.libraryNameSuffix)\
\(isShared ? "_dynamic.dylib" : ".a")
"""
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,12 @@ public final class GenericUnixToolchain: Toolchain {
for sanitizer: Sanitizer,
targetTriple: Triple,
isShared: Bool
) throws -> String {
) throws -> String? {
guard let runtimeLibraryName = sanitizer.runtimeLibraryName else {
return nil
}
let environment = (targetTriple.environment == .android) ? "-android" : ""
return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName)\(environment).a"
return "libclang_rt.\(runtimeLibraryName)-\(targetTriple.archName)\(environment).a"
}

public func addPlatformSpecificCommonFrontendOptions(
Expand Down
3 changes: 2 additions & 1 deletion Sources/SwiftDriver/Toolchains/Toolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ public protocol Toolchain {
targetInfo: FrontendTargetInfo
) throws -> ResolvedTool

/// Returns the runtime library name for a given sanitizer (or nil if the sanitizer does not have a runtime library)
func runtimeLibraryName(
for sanitizer: Sanitizer,
targetTriple: Triple,
isShared: Bool
) throws -> String
) throws -> String?

func platformSpecificInterpreterEnvironmentVariables(
env: ProcessEnvironmentBlock,
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ public final class WebAssemblyToolchain: Toolchain {
for sanitizer: Sanitizer,
targetTriple: Triple,
isShared: Bool
) throws -> String {
) throws -> String? {
switch sanitizer {
case .address:
return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName).a"
return "libclang_rt.\(sanitizer.runtimeLibraryName!)-\(targetTriple.archName).a"
default:
throw Error.sanitizersUnsupportedForTarget(targetTriple.triple)
}
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftDriver/Toolchains/WindowsToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,17 @@ extension WindowsToolchain.ToolchainValidationError {
public var globalDebugPathRemapping: String? { nil }

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

// FIXME(compnerd) when should `clang_rt.ubsan_standalone_cxx` be used?
if sanitizer == .undefinedBehavior {
return "clang_rt.ubsan_standalone.lib"
}
return "clang_rt.\(sanitizer.libraryName).lib"
if sanitizer == .memtag_stack {
throw ToolchainValidationError.unsupportedSanitizer(sanitizer)
}
return "clang_rt.\(sanitizer.runtimeLibraryName!).lib"
}

public func validateArgs(_ parsedOptions: inout ParsedOptions,
Expand Down
16 changes: 14 additions & 2 deletions Sources/SwiftDriver/Utilities/Sanitizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,27 @@ public enum Sanitizer: String, Hashable {
/// Scudo hardened allocator
case scudo

/// The name inside the `compiler_rt` library path (e.g. libclang_rt.{name}.a)
var libraryName: String {
/// Memory-Tagging-based stack sanitizer
case memtag_stack = "memtag-stack"

/// Does this sanitizer have a runtime library
var hasRuntimeLibrary: Bool {
if self == .memtag_stack {
return false
}
return true
}

/// The name inside the `compiler_rt` runtime library path (e.g. libclang_rt.{name}.a)
var runtimeLibraryName: String? {
switch self {
case .address: return "asan"
case .address_stable_abi: return "asan_abi"
case .thread: return "tsan"
case .undefinedBehavior: return "ubsan"
case .fuzzer: return "fuzzer"
case .scudo: return "scudo"
case .memtag_stack: return nil
}
}
}
10 changes: 10 additions & 0 deletions Tests/SwiftDriverTests/SwiftDriverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3101,6 +3101,16 @@ final class SwiftDriverTests: XCTestCase {
XCTAssertJobInvocationMatches(jobs[2], .flag("-fsanitize=undefined"))
}

do {
// memory tagging stack sanitizer
var driver = try Driver(args: commonArgs + ["-sanitize=memtag-stack"])
let jobs = try driver.planBuild().removingAutolinkExtractJobs()

XCTAssertEqual(jobs.count, 3)
XCTAssertJobInvocationMatches(jobs[0], .flag("-sanitize=memtag-stack"))
// No runtime for memtag-stack - thus no linker arg required
}

// FIXME: This test will fail when run on macOS, because the driver uses
// the existence of the runtime support libraries to determine if
// a sanitizer is supported. Until we allow cross-compiling with
Expand Down
Loading