https://github.com/jinge90 created https://github.com/llvm/llvm-project/pull/76127
In offloading scenario, the whole compiling process consists of device and host compilation phase, device and host code will be bundled together. Address sanitizer can be enabled in either one or both compilation phases via fsanitize-target=host|device|both. The meaning of each value is: -fsanitize-target=host AsanPass only enabled in host code -fsanitize-target=device AsanPass only enabled in device code -fsanitize-target=both AsanPass enabled in both host and device code The default value is 'both'. >From 48684cf6397ddc7d1a941fdbfbb9e28591bf0240 Mon Sep 17 00:00:00 2001 From: jinge90 <ge....@intel.com> Date: Thu, 21 Dec 2023 15:36:37 +0800 Subject: [PATCH] [ASan][Driver] Add sanitize-target flag to support enabling ASan in device or host compilation In offloading scenario, the whole compiling process consists of device and host compilation phase, device and host code will be bundled together. Address sanitizer can be enabled in either one or both compilation phases via fsanitize-target=host|device|both. The meaning of each value is: -fsanitize-target=host AsanPass only enabled in host code -fsanitize-target=device AsanPass only enabled in device code -fsanitize-target=both AsanPass enabled in both host and device code The default value is 'both'. --- clang/include/clang/Basic/CodeGenOptions.def | 4 +++ clang/include/clang/Basic/Sanitizers.h | 4 +++ clang/include/clang/Driver/Options.td | 12 +++++++ clang/include/clang/Driver/SanitizerArgs.h | 7 +++- clang/lib/Basic/Sanitizers.cpp | 23 +++++++++++++ clang/lib/CodeGen/BackendUtil.cpp | 19 ++++++++++- clang/lib/Driver/SanitizerArgs.cpp | 34 +++++++++++++++++++ clang/test/Driver/sycl-sanitize-target.cpp | 29 ++++++++++++++++ .../Instrumentation/AddressSanitizerOptions.h | 8 +++++ 9 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 clang/test/Driver/sycl-sanitize-target.cpp diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 0acb5ae134ea24..af44b98e9d046b 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -224,6 +224,10 @@ ENUM_CODEGENOPT(SanitizeAddressUseAfterReturn, llvm::AsanDetectStackUseAfterReturnMode, 2, llvm::AsanDetectStackUseAfterReturnMode::Runtime ) ///< Set detection mode for stack-use-after-return. +ENUM_CODEGENOPT( + SanitizeTargetsToEnable, llvm::AsanTargetsToEnable, 2, + llvm::AsanTargetsToEnable::Both) ///< Set targets to enable sanitizer + /// passes in offloading scenario. CODEGENOPT(SanitizeAddressPoisonCustomArrayCookie, 1, 0) ///< Enable poisoning operator new[] which is not a replaceable ///< global allocation function in AddressSanitizer diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index c890242269b334..e3fe35ed285dc3 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -211,6 +211,10 @@ StringRef AsanDetectStackUseAfterReturnModeToString( llvm::AsanDetectStackUseAfterReturnMode AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr); +llvm::AsanTargetsToEnable +AsanTargetsToEnableFromString(StringRef asanTargetsStr); + +StringRef AsanTargetsToEnableToString(llvm::AsanTargetsToEnable target); } // namespace clang #endif // LLVM_CLANG_BASIC_SANITIZERS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1b02087425b751..b9a3b3b05b48af 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2462,6 +2462,18 @@ def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-unde "when emitting check metadata.">, MarshallingInfoInt<CodeGenOpts<"EmitCheckPathComponentsToStrip">, "0", "int">; +def sanitize_targets_EQ + : Joined<["-"], "fsanitize-target=">, + MetaVarName<"<target>">, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Select target to enable sanitizer in offloading scenario, " + "valid targets are host, device, both(both host and device " + "enabled).">, + Group<f_clang_Group>, + Values<"host,device,both">, + NormalizedValuesScope<"llvm::AsanTargetsToEnable">, + NormalizedValues<["Host", "Device", "Both"]>, + MarshallingInfoEnum<CodeGenOpts<"SanitizeTargetsToEnable">, "Both">; } // end -f[no-]sanitize* flags def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">, diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 07070ec4fc0653..aaa896a02eb142 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -67,6 +67,8 @@ class SanitizerArgs { bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; + llvm::AsanTargetsToEnable AsanTargetsToEnable = + llvm::AsanTargetsToEnable::Both; std::string MemtagMode; @@ -79,7 +81,10 @@ class SanitizerArgs { bool needsStableAbi() const { return StableABI; } bool needsMemProfRt() const { return NeedsMemProfRt; } - bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); } + bool needsAsanRt() const { + bool AsanIsNotDeviceOnly = + !(AsanTargetsToEnable == llvm::AsanTargetsToEnable::Device); + return Sanitizers.has(SanitizerKind::Address) && AsanIsNotDeviceOnly; } bool needsHwasanRt() const { return Sanitizers.has(SanitizerKind::HWAddress); } diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 62ccdf8e9bbf28..05eda31c3f7ffd 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -112,4 +112,27 @@ AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr) { .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid); } +llvm::AsanTargetsToEnable +AsanTargetsToEnableFromString(StringRef asanTargetsStr) { + return llvm::StringSwitch<llvm::AsanTargetsToEnable>(asanTargetsStr) + .Case("host", llvm::AsanTargetsToEnable::Host) + .Case("device", llvm::AsanTargetsToEnable::Device) + .Case("both", llvm::AsanTargetsToEnable::Both) + .Default(llvm::AsanTargetsToEnable::Invalid); +} + +StringRef AsanTargetsToEnableToString(llvm::AsanTargetsToEnable target) { + switch (target) { + case llvm::AsanTargetsToEnable::Host: + return "host"; + case llvm::AsanTargetsToEnable::Device: + return "device"; + case llvm::AsanTargetsToEnable::Both: + return "both"; + case llvm::AsanTargetsToEnable::Invalid: + return "invalid"; + } + return "invalid"; +} + } // namespace clang diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 480410db1021b7..f4006270a13229 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -700,7 +700,24 @@ static void addSanitizers(const Triple &TargetTriple, DestructorKind)); } }; - ASanPass(SanitizerKind::Address, false); + // AddressSanitizer can be enabled in offloading scenario to detect bugs in + // both host and device code. Users may use '-fsanitizer-targets' flag to + // enable this only on the host or only on the device. The default behavior + // is to enable AddressSanitizer in both host and device compilation. + // Currently, we support this in SYCL compiler. + bool IgnoreAsanPass = false; + if (LangOpts.isSYCL()) { + llvm::AsanTargetsToEnable AsanTarget = + CodeGenOpts.getSanitizeTargetsToEnable(); + if ((AsanTarget == llvm::AsanTargetsToEnable::Device) && + LangOpts.SYCLIsHost) + IgnoreAsanPass = true; + if ((AsanTarget == llvm::AsanTargetsToEnable::Host) && + LangOpts.SYCLIsDevice) + IgnoreAsanPass = true; + } + if (!IgnoreAsanPass) + ASanPass(SanitizerKind::Address, false); ASanPass(SanitizerKind::KernelAddress, true); auto HWASanPass = [&](SanitizerMask Mask, bool CompileKernel) { diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index ad68c086b71790..8805e4c915cd6e 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1010,6 +1010,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, AsanUseAfterReturn = parsedAsanUseAfterReturn; } + if (const auto *Arg = Args.getLastArg(options::OPT_sanitize_targets_EQ)) { + auto parsedAsanTargetsToEnable = + AsanTargetsToEnableFromString(Arg->getValue()); + if (parsedAsanTargetsToEnable == llvm::AsanTargetsToEnable::Invalid && + DiagnoseErrors) { + TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) + << Arg->getSpelling() << Arg->getValue(); + } + AsanTargetsToEnable = parsedAsanTargetsToEnable; + } + } else { AsanUseAfterScope = false; // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address. @@ -1138,6 +1149,29 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, GPUSanitize = true; } + // In offloading scenario, the whole compiling process consists of device and + // host compilation phase, device and host code will be bundled together. + // Address sanitizer can be enabled in either one or both compilation phases + // via fsanitize-target=host|device|both. This flag must be passed to both + // device and host compilation to indicate whether to enable ASanPass in + // current phase. In SYCL, when SYCL compiler's target triple is SPIR, we are + // in device compilation phase, if target triple is not SPIR and '-fsycl' is + // used, we are in host compilation phase. + if (TC.getTriple().isSPIR()) { + if (Sanitizers.has(SanitizerKind::Address)) { + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-target=" + + AsanTargetsToEnableToString(AsanTargetsToEnable))); + } + } else { + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false) && + Sanitizers.has(SanitizerKind::Address)) { + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-target=" + + AsanTargetsToEnableToString(AsanTargetsToEnable))); + } + } + // Translate available CoverageFeatures to corresponding clang-cc1 flags. // Do it even if Sanitizers.empty() since some forms of coverage don't require // sanitizers. diff --git a/clang/test/Driver/sycl-sanitize-target.cpp b/clang/test/Driver/sycl-sanitize-target.cpp new file mode 100644 index 00000000000000..c927d3b4e0f1a8 --- /dev/null +++ b/clang/test/Driver/sycl-sanitize-target.cpp @@ -0,0 +1,29 @@ +// UNSUPPORTED: system-windows + +// Check whether ASan runtime libraries are linked or not when +// fsanitize-target=host|device|both. The ASan runtime libraries +// are NOT needed for device compilation in offloading scenario. + +// RUN: %clangxx -fsycl -fsanitize=address %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL-ASAN-DEFAULT %s +// SYCL-ASAN-DEFAULT: "{{.*}}/ld" +// SYCL-ASAN-DEFAULT-SAME: "{{.*}}/libclang_rt.asan{{.*}}.a" + +// RUN: %clangxx -fsycl -fsanitize=address -fsanitize-target=host %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL-ASAN-HOST %s +// SYCL-ASAN-HOST: "{{.*}}/ld" +// SYCL-ASAN-HOST-SAME: "{{.*}}/libclang_rt.asan{{.*}}.a" + +// RUN: %clangxx -fsycl -fsanitize=address -fsanitize-target=both %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL-ASAN-BOTH %s +// SYCL-ASAN-BOTH: "{{.*}}/ld" +// SYCL-ASAN-BOTH-SAME: "{{.*}}/libclang_rt.asan{{.*}}.a" + +// RUN: %clangxx -fsycl -fsanitize=address -fsanitize-target=device %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL-ASAN-DEVICE %s +// SYCL-ASAN-DEVICE: "{{.*}}/ld" +// SYCL-ASAN-DEVICE-NOT: "{{.*}}/libclang_rt.asan{{.*}}.a" + +// RUN: not %clangxx -fsycl -fsanitize=address -fsanitize-target=YYY %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL-ASAN-INVALID %s +// SYCL-ASAN-INVALID: error: unsupported argument 'YYY' diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h index d697b72cde05e9..80984c2bd3e6a3 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h @@ -34,6 +34,14 @@ enum class AsanDetectStackUseAfterReturnMode { Invalid, ///< Not a valid detect mode. }; +/// Targets to enable address sanitizer pass in offloading scenario. +enum class AsanTargetsToEnable { + Host, ///< Only enable AddressSanitizerPass for host compilation. + Device, ///< Only enable AddressSanitizerPass for device compilation. + Both, ///< Enable AddressSanitizerPass for both host and device compilation. + Invalid ///< Not a valid detect mode. +}; + } // namespace llvm #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits