From a518218015bae92e0c9587575566af6bd5dcdc47 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 13 May 2025 14:23:12 +0900 Subject: [PATCH 1/2] Align Clang resource directory lookup with Clang driver logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we used `Triple.platformName(conflatingDarwin: true)` to derive the OS directory under /lib/, which was documented as “the name clang uses”. However, this was in fact closer to what Swift itself uses for resource directories, and it diverged from Clang’s behavior in some cases. For example, for wasm32-unknown-wasip1-threads, Swift uses "wasi" as the OS name, but Clang uses "wasip1", matching the result of Triple::getOS, in their resource directory lookup. This patch aligns the behavior with Clang’s logic for looking up the compiler resource directory libraries. --- .../Jobs/Toolchain+LinkerSupport.swift | 7 +----- .../Utilities/Triple+Platforms.swift | 23 ++++++++++++++++++- Tests/SwiftDriverTests/TripleTests.swift | 9 ++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index ab4cfe0f4..f2fad3ad0 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -26,12 +26,7 @@ extension Toolchain { for targetInfo: FrontendTargetInfo, parsedOptions: inout ParsedOptions ) throws -> VirtualPath { - var platform = targetInfo.target.triple.platformName(conflatingDarwin: true)! - // compiler-rt moved these Android sanitizers into `lib/linux/` a couple - // years ago, llvm/llvm-project@a68ccba, so look for them there instead. - if platform == "android" { - platform = "linux" - } + let platform = targetInfo.target.triple.clangOSLibName // NOTE(compnerd) Windows uses the per-target runtime directory for the // Windows runtimes. This should also be done for the other platforms, but diff --git a/Sources/SwiftDriver/Utilities/Triple+Platforms.swift b/Sources/SwiftDriver/Utilities/Triple+Platforms.swift index 0841046ae..d66c17314 100644 --- a/Sources/SwiftDriver/Utilities/Triple+Platforms.swift +++ b/Sources/SwiftDriver/Utilities/Triple+Platforms.swift @@ -303,7 +303,28 @@ extension Triple { } } - /// The platform name, i.e. the name clang uses to identify this target in its + + /// The "os" component of the Clang compiler resource library directory (`/lib/`). + /// Must be kept in sync with Clang driver: + /// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.4/clang/lib/Driver/ToolChain.cpp#L690 + @_spi(Testing) public var clangOSLibName: String { + guard let os else { + return osName + } + if os.isDarwin { + return "darwin" + } + + switch os { + case .freeBSD: return "freebsd" + case .netbsd: return "netbsd" + case .openbsd: return "openbsd" + case .aix: return "aix" + default: return osName + } + } + + /// The platform name, i.e. the name Swift uses to identify this target in its /// resource directory. /// /// - Parameter conflatingDarwin: If true, all Darwin platforms will be diff --git a/Tests/SwiftDriverTests/TripleTests.swift b/Tests/SwiftDriverTests/TripleTests.swift index 311e77fc4..ff037d26e 100644 --- a/Tests/SwiftDriverTests/TripleTests.swift +++ b/Tests/SwiftDriverTests/TripleTests.swift @@ -1317,6 +1317,15 @@ final class TripleTests: XCTestCase { shouldHaveJetPacks: true) } + func testClangOSLibName() { + XCTAssertEqual("darwin", Triple("x86_64-apple-macosx").clangOSLibName) + XCTAssertEqual("darwin", Triple("arm64-apple-ios13.0").clangOSLibName) + XCTAssertEqual("linux", Triple("aarch64-unknown-linux-android24").clangOSLibName) + XCTAssertEqual("wasi", Triple("wasm32-unknown-wasi").clangOSLibName) + XCTAssertEqual("wasip1", Triple("wasm32-unknown-wasip1-threads").clangOSLibName) + XCTAssertEqual("none", Triple("arm64-unknown-none").clangOSLibName) + } + func testToolchainSelection() { let diagnostics = DiagnosticsEngine() struct None { } From 2c8b4d73143da122736327019933fd98eb97b175 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 13 May 2025 14:41:49 +0900 Subject: [PATCH 2/2] Add WASI as a supported target for sanitizers We are adding support for sanitizers on WASI targets. This commit adds driver support by unblocking hard-coded checks and forwarding sanitizer flags to clang linker driver. --- Sources/SwiftDriver/Driver/Driver.swift | 2 +- .../WebAssemblyToolchain+LinkerSupport.swift | 8 +++- .../Toolchains/WebAssemblyToolchain.swift | 7 +++- Tests/SwiftDriverTests/SwiftDriverTests.swift | 41 +++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index db11ab3cc..9e856531c 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -2751,7 +2751,7 @@ extension Driver { } // Check that we're one of the known supported targets for sanitizers. - if !(targetTriple.isWindows || targetTriple.isDarwin || targetTriple.os == .linux) { + if !(targetTriple.isWindows || targetTriple.isDarwin || targetTriple.os == .linux || targetTriple.os == .wasi) { diagnosticEngine.emit( .error_unsupported_opt_for_target( arg: "-sanitize=", diff --git a/Sources/SwiftDriver/Jobs/WebAssemblyToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WebAssemblyToolchain+LinkerSupport.swift index 3ea3a2709..aee547b52 100644 --- a/Sources/SwiftDriver/Jobs/WebAssemblyToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WebAssemblyToolchain+LinkerSupport.swift @@ -165,8 +165,12 @@ extension WebAssemblyToolchain { // Delegate to Clang for sanitizers. It will figure out the correct linker // options. - guard sanitizers.isEmpty else { - throw Error.sanitizersUnsupportedForTarget(targetTriple.triple) + if linkerOutputType == .executable && !sanitizers.isEmpty { + let sanitizerNames = sanitizers + .map { $0.rawValue } + .sorted() // Sort so we get a stable, testable order + .joined(separator: ",") + commandLine.appendFlag("-fsanitize=\(sanitizerNames)") } if parsedOptions.hasArgument(.profileGenerate) { diff --git a/Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift b/Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift index 25cdb90c0..8db1558dc 100644 --- a/Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WebAssemblyToolchain.swift @@ -140,7 +140,12 @@ public final class WebAssemblyToolchain: Toolchain { targetTriple: Triple, isShared: Bool ) throws -> String { - throw Error.sanitizersUnsupportedForTarget(targetTriple.triple) + switch sanitizer { + case .address: + return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName).a" + default: + throw Error.sanitizersUnsupportedForTarget(targetTriple.triple) + } } public func platformSpecificInterpreterEnvironmentVariables(env: [String : String], diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index e3779ee48..fccc3d969 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -2877,6 +2877,47 @@ final class SwiftDriverTests: XCTestCase { XCTAssertTrue(linkCmd.contains(.flag("-fsanitize=address"))) } #endif + + func checkWASITarget(target: String, clangOSDir: String) throws { + try withTemporaryDirectory { resourceDir in + var env = ProcessEnv.vars + env["SWIFT_DRIVER_SWIFT_AUTOLINK_EXTRACT_EXEC"] = "/garbage/swift-autolink-extract" + + let asanRuntimeLibPath = resourceDir.appending(components: [ + "clang", "lib", clangOSDir, "libclang_rt.asan-wasm32.a" + ]) + try localFileSystem.writeFileContents(asanRuntimeLibPath) { + $0.send("garbage") + } + try localFileSystem.writeFileContents(resourceDir.appending(components: "wasi", "static-executable-args.lnk")) { + $0.send("garbage") + } + + var driver = try Driver( + args: commonArgs + [ + "-target", target, "-sanitize=address", + "-resource-dir", resourceDir.pathString + ], + env: env + ) + let plannedJobs = try driver.planBuild() + + XCTAssertEqual(plannedJobs.count, 4) + + let compileJob = plannedJobs[0] + let compileCmd = compileJob.commandLine + XCTAssertTrue(compileCmd.contains(.flag("-sanitize=address"))) + + let linkJob = plannedJobs[3] + let linkCmd = linkJob.commandLine + XCTAssertTrue(linkCmd.contains(.flag("-fsanitize=address"))) + } + } + do { + try checkWASITarget(target: "wasm32-unknown-wasi", clangOSDir: "wasi") + try checkWASITarget(target: "wasm32-unknown-wasip1", clangOSDir: "wasip1") + try checkWASITarget(target: "wasm32-unknown-wasip1-threads", clangOSDir: "wasip1") + } } func testSanitizerCoverageArgs() throws {