diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -481,7 +481,8 @@ "ROPI is not compatible with c++">; def err_stack_tagging_requires_hardware_feature : Error< - "'-fsanitize=memtag' requires hardware support (+memtag)">; + "'-fsanitize=memtag-stack' requires hardware support (+memtag). For Armv8, " + "try compiling with -march=armv8a+memtag.">; def err_cmse_pi_are_incompatible : Error< "cmse is not compatible with %select{RWPI|ROPI}0">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -45,7 +45,10 @@ FEATURE(hwaddress_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress)) -FEATURE(memtag_sanitizer, LangOpts.Sanitize.has(SanitizerKind::MemTag)) +FEATURE(memtag_stack, + LangOpts.Sanitize.has(SanitizerKind::MemtagStack)) +FEATURE(memtag_heap, + LangOpts.Sanitize.has(SanitizerKind::MemtagHeap)) FEATURE(xray_instrument, LangOpts.XRayInstrument) FEATURE(undefined_behavior_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined)) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -56,7 +56,9 @@ SANITIZER("kernel-hwaddress", KernelHWAddress) // A variant of AddressSanitizer using AArch64 MTE extension. -SANITIZER("memtag", MemTag) +SANITIZER("memtag-stack", MemtagStack) +SANITIZER("memtag-heap", MemtagHeap) +SANITIZER_GROUP("memtag", MemTag, MemtagStack | MemtagHeap) // MemorySanitizer SANITIZER("memory", Memory) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1641,6 +1641,9 @@ def fno_sanitize_address_outline_instrumentation : Flag<["-"], "fno-sanitize-address-outline-instrumentation">, Group, HelpText<"Use default code inlining logic for the address sanitizer">; +def fsanitize_memtag_mode_EQ : Joined<["-"], "fsanitize-memtag-mode=">, + Group, + HelpText<"Set default MTE mode to 'sync' (default) or 'async'.">; def fsanitize_hwaddress_experimental_aliasing : Flag<["-"], "fsanitize-hwaddress-experimental-aliasing">, Group, diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,8 @@ llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; + std::string MemtagMode; + public: /// Parses the sanitizer arguments from an argument list. SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, @@ -97,6 +99,18 @@ bool needsStatsRt() const { return Stats; } bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); } + bool hasMemTag() const { return hasMemtagHeap() || hasMemtagStack(); } + bool hasMemtagHeap() const { + return Sanitizers.has(SanitizerKind::MemtagHeap); + } + bool hasMemtagStack() const { + return Sanitizers.has(SanitizerKind::MemtagStack); + } + const std::string &getMemtagMode() const { + assert(!MemtagMode.empty()); + return MemtagMode; + } + bool requiresPIE() const; bool needsUnwindTables() const; bool needsLTO() const; diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -458,8 +458,8 @@ !isInNoSanitizeList(SanitizerKind::KernelHWAddress, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress); - if (getLangOpts().Sanitize.has(SanitizerKind::MemTag) && - !isInNoSanitizeList(SanitizerKind::MemTag, Fn, Loc)) + if (getLangOpts().Sanitize.has(SanitizerKind::MemtagStack) && + !isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); if (getLangOpts().Sanitize.has(SanitizerKind::Thread) && diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -780,7 +780,7 @@ if (SanOpts.hasOneOf(SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress)) Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress); - if (SanOpts.has(SanitizerKind::MemTag)) + if (SanOpts.has(SanitizerKind::MemtagStack)) Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); if (SanOpts.has(SanitizerKind::Thread)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -735,7 +735,7 @@ LangOptions::SignReturnAddressScopeKind::None) getModule().addModuleFlag(llvm::Module::Override, "sign-return-address-buildattr", 1); - if (LangOpts.Sanitize.has(SanitizerKind::MemTag)) + if (LangOpts.Sanitize.has(SanitizerKind::MemtagStack)) getModule().addModuleFlag(llvm::Module::Override, "tag-stack-memory-buildattr", 1); diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -44,8 +44,8 @@ static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | - SanitizerKind::MemTag | SanitizerKind::Memory | - SanitizerKind::KernelMemory | SanitizerKind::Leak | + SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | + SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::DataFlow | SanitizerKind::Fuzzer | @@ -73,7 +73,7 @@ SanitizerKind::CFIUnrelatedCast; static const SanitizerMask CompatibleWithMinimalRuntime = TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack | - SanitizerKind::MemTag; + SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -651,6 +651,17 @@ MsanParamRetval = false; } + if (AllAddedKinds & SanitizerKind::MemTag) { + StringRef S = + Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "sync"); + if (S == "async" || S == "sync") { + MemtagMode = S.str(); + } else { + D.Diag(clang::diag::err_drv_invalid_value_with_suggestion) + << "-fsanitize-memtag-mode=" << S << "{async, sync}"; + } + } + if (AllAddedKinds & SanitizerKind::Thread) { TsanMemoryAccess = Args.hasFlag( options::OPT_fsanitize_thread_memory_access, @@ -1231,7 +1242,8 @@ << "-fvisibility="; } - if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs)) + if (Sanitizers.has(SanitizerKind::MemtagStack) && + !hasTargetFeatureMTE(CmdArgs)) TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature); } diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1007,6 +1007,19 @@ if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); + if (SanArgs.hasMemTag()) { + if (!TC.getTriple().isAndroid()) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << ("-fsanitize=memtag*") << TC.getTriple().str(); + } + CmdArgs.push_back( + Args.MakeArgString("--android-memtag-mode=" + SanArgs.getMemtagMode())); + if (SanArgs.hasMemtagHeap()) + CmdArgs.push_back("--android-memtag-heap"); + if (SanArgs.hasMemtagStack()) + CmdArgs.push_back("--android-memtag-stack"); + } + return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } diff --git a/clang/test/CodeGen/memtag-attr.cpp b/clang/test/CodeGen/memtag-attr.cpp --- a/clang/test/CodeGen/memtag-attr.cpp +++ b/clang/test/CodeGen/memtag-attr.cpp @@ -4,16 +4,27 @@ // RUN: %clang_cc1 -triple aarch64-unknown-linux -disable-O0-optnone \ // RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: %clang_cc1 -triple aarch64-unknown-linux -fsanitize=memtag \ +// RUN: %clang_cc1 -triple aarch64-unknown-linux -fsanitize=memtag-stack \ // RUN: -disable-O0-optnone -emit-llvm -o - %s | \ // RUN: FileCheck -check-prefix=CHECK-MEMTAG %s -int HasSanitizeMemTag() { return 1; } -// CHECK-NO: {{Function Attrs: mustprogress noinline nounwind$}} -// CHECK-MEMTAG: Function Attrs: mustprogress noinline nounwind sanitize_memtag +// RUN: %clang --target=aarch64-unknown-linux -march=armv8a+memtag \ +// RUN: -fsanitize=memtag -disable-O0-optnone -S -emit-llvm -o - %s | \ +// RUN: FileCheck -check-prefix=CHECK-MEMTAG %s + +extern "C" int HasSanitizeMemTag() { return 1; } +// CHECK-NO: Function Attrs +// CHECK-NO-NOT: sanitize_memtag +// CHECK-NO-NEXT: define {{.*}} @HasSanitizeMemTag( +// CHECK-MEMTAG: Function Attrs: {{.*}} sanitize_memtag +// CHECK-MEMTAG-NEXT: define {{.*}} @HasSanitizeMemTag( -__attribute__((no_sanitize("memtag"))) int NoSanitizeQuoteAddress() { +extern "C" __attribute__((no_sanitize("memtag"))) int NoSanitizeQuoteAddress() { return 0; } -// CHECK-NO: {{Function Attrs: mustprogress noinline nounwind$}} -// CHECK-MEMTAG: {{Function Attrs: mustprogress noinline nounwind$}} +// CHECK-NO: Function Attrs +// CHECK-NO-NOT: sanitize_memtag +// CHECK-NO-NEXT: define {{.*}} @NoSanitizeQuoteAddress( +// CHECK-MEMTAG: Function Attrs +// CHECK-MEMTAG-NOT: sanitize_memtag +// CHECK-MEMTAG-NEXT: define {{.*}} @NoSanitizeQuoteAddress( diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -195,13 +195,13 @@ // RUN: %clang -target aarch64-linux -fsanitize=memtag -march=armv8-a+memtag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-MT // CHECK-SANMT-MT: "-target-feature" "+mte" -// CHECK-SANMT-MT-SAME: "-fsanitize=memtag" +// CHECK-SANMT-MT-SAME: "-fsanitize=memtag-stack,memtag-heap" // RUN: %clang -target aarch64-linux -fsanitize=memtag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-NOMT-0 -// CHECK-SANMT-NOMT-0: '-fsanitize=memtag' requires hardware support (+memtag) +// CHECK-SANMT-NOMT-0: '-fsanitize=memtag-stack' requires hardware support (+memtag) // RUN: %clang -target aarch64-linux -fsanitize=memtag -I +mte %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-NOMT-1 -// CHECK-SANMT-NOMT-1: '-fsanitize=memtag' requires hardware support (+memtag) +// CHECK-SANMT-NOMT-1: '-fsanitize=memtag-stack' requires hardware support (+memtag) // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE // RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fsanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE @@ -801,7 +801,7 @@ // CHECK-INTSAN-MINIMAL: "-fsanitize-minimal-runtime" // RUN: %clang -target aarch64-linux-android -march=armv8-a+memtag -fsanitize=memtag -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MEMTAG-MINIMAL -// CHECK-MEMTAG-MINIMAL: "-fsanitize=memtag" +// CHECK-MEMTAG-MINIMAL: "-fsanitize=memtag-stack,memtag-heap" // CHECK-MEMTAG-MINIMAL: "-fsanitize-minimal-runtime" // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize=function -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-MINIMAL diff --git a/clang/test/Driver/memtag-ld.c b/clang/test/Driver/memtag-ld.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/memtag-ld.c @@ -0,0 +1,46 @@ +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-NO-HEAP,CHECK-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-NO-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag -fsanitize-memtag-mode=async %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack -fsanitize-memtag-mode=async %s 2>&1 \ +// RUN: | FileCheck %s \ +// RUN: --check-prefixes=CHECK-ASYNC,CHECK-NO-HEAP,CHECK-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=async %s 2>&1 \ +// RUN: | FileCheck %s \ +// RUN: --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-NO-STACK + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=asymm %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-INVALID-MODE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack -fsanitize=memtag-heap \ +// RUN: -fsanitize-memtag-mode=asymm -fno-sanitize=memtag %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-NONE + +// CHECK-ASYNC: ld{{.*}} "--android-memtag-mode=async" +// CHECK-SYNC: ld{{.*}} "--android-memtag-mode=sync" +// CHECK-HEAP: "--android-memtag-heap" +// CHECK-NO-HEAP-NOT: "--android-memtag-heap" +// CHECK-STACK: "--android-memtag-stack" +// CHECK-NO-STACK-NOT: "--android-memtag-stack" +// CHECK-INVALID-MODE: invalid value 'asymm' in '-fsanitize-memtag-mode=', +// CHECK-INVALID-MODE-SAME: expected one of: {async, sync} +// CHECK-NONE-NOT: ld{{.*}} "--android-memtag + +void f() {} diff --git a/clang/test/Driver/memtag.c b/clang/test/Driver/memtag-stack.c rename from clang/test/Driver/memtag.c rename to clang/test/Driver/memtag-stack.c diff --git a/clang/test/Lexer/has_feature_memtag.cpp b/clang/test/Lexer/has_feature_memtag.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Lexer/has_feature_memtag.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -E -fsanitize=memtag-stack %s -o - | FileCheck --check-prefix=CHECK-MEMTAG-STACK %s +// RUN: %clang_cc1 -E -fsanitize=memtag-heap %s -o - | FileCheck --check-prefix=CHECK-MEMTAG-HEAP %s +// RUN: %clang -E -fsanitize=memtag --target=aarch64-unknown-linux -march=armv8a+memtag %s -o - \ +// RUN: | FileCheck --check-prefixes=CHECK-MEMTAG-STACK,CHECK-MEMTAG-HEAP %s +// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-MEMTAG %s + +#if __has_feature(memtag_stack) +int MemTagSanitizerStack(); +#else +int MemTagSanitizerNoStack(); +#endif + +#if __has_feature(memtag_heap) +int MemTagSanitizerHeap(); +#else +int MemTagSanitizerNoHeap(); +#endif + +// CHECK-MEMTAG-STACK: MemTagSanitizerStack +// CHECK-MEMTAG-HEAP: MemTagSanitizerHeap + +// CHECK-NO-MEMTAG: MemTagSanitizerNoStack +// CHECK-NO-MEMTAG: MemTagSanitizerNoHeap diff --git a/clang/test/Lexer/has_feature_memtag_sanitizer.cpp b/clang/test/Lexer/has_feature_memtag_sanitizer.cpp deleted file mode 100644 --- a/clang/test/Lexer/has_feature_memtag_sanitizer.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 -E -fsanitize=memtag %s -o - | FileCheck --check-prefix=CHECK-MEMTAG %s -// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-MEMTAG %s - -#if __has_feature(memtag_sanitizer) -int MemTagSanitizerEnabled(); -#else -int MemTagSanitizerDisabled(); -#endif - -// CHECK-MEMTAG: MemTagSanitizerEnabled -// CHECK-NO-MEMTAG: MemTagSanitizerDisabled