hctim updated this revision to Diff 405839.
hctim marked an inline comment as done.
hctim added a comment.

Address Ray's comments, and made it so that stack MTE doesn't imply heap.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118948/new/

https://reviews.llvm.org/D118948

Files:
  clang/include/clang/Basic/DiagnosticDriverKinds.td
  clang/include/clang/Basic/Features.def
  clang/include/clang/Basic/Sanitizers.def
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/SanitizerArgs.h
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/SanitizerArgs.cpp
  clang/lib/Driver/ToolChains/CommonArgs.cpp
  clang/test/CodeGen/memtag-attr.cpp
  clang/test/Driver/fsanitize.c
  clang/test/Driver/memtag-ld.c
  clang/test/Driver/memtag-stack.c
  clang/test/Driver/memtag.c
  clang/test/Lexer/has_feature_memtag_heap.cpp
  clang/test/Lexer/has_feature_memtag_sanitizer.cpp
  clang/test/Lexer/has_feature_memtag_stack.cpp
  lld/ELF/Config.h
  lld/ELF/Driver.cpp
  lld/ELF/Options.td
  lld/ELF/SyntheticSections.cpp
  lld/ELF/SyntheticSections.h
  lld/ELF/Writer.cpp
  lld/test/ELF/aarch64-memtag-android-abi.s
  llvm/include/llvm/BinaryFormat/ELF.h

Index: llvm/include/llvm/BinaryFormat/ELF.h
===================================================================
--- llvm/include/llvm/BinaryFormat/ELF.h
+++ llvm/include/llvm/BinaryFormat/ELF.h
@@ -1531,6 +1531,22 @@
   NT_GNU_PROPERTY_TYPE_0 = 5,
 };
 
+// Android note types.
+enum {
+  NT_ANDROID_TYPE_IDENT = 1,
+  NT_ANDROID_TYPE_KUSER = 3,
+  NT_ANDROID_TYPE_MEMTAG = 4,
+};
+
+enum {
+  NT_MEMTAG_LEVEL_DEFAULT = 0,
+  NT_MEMTAG_LEVEL_ASYNC = 1,
+  NT_MEMTAG_LEVEL_SYNC = 2,
+  NT_MEMTAG_LEVEL_MASK = 3,
+  NT_MEMTAG_HEAP = 4,
+  NT_MEMTAG_STACK = 8,
+};
+
 // Property types used in GNU_PROPERTY_TYPE_0 notes.
 enum : unsigned {
   GNU_PROPERTY_STACK_SIZE = 1,
Index: lld/test/ELF/aarch64-memtag-android-abi.s
===================================================================
--- /dev/null
+++ lld/test/ELF/aarch64-memtag-android-abi.s
@@ -0,0 +1,78 @@
+# Old versions of Android (Android 11 & 12) have very strict parsing logic on
+# the layout of the ELF note. This test serves as a "hey, you're going to break
+# the ABI" check. Basically below is the copied version of the Android parsing
+# logic. We create a no-op aarch64 binary with an elf note, and then consume it
+# using the parsing logic on the host system. Because we don't pull in any
+# libraries or headers, this should be runnable on any system that uses linux
+# (technically, any system that can parse ELF, but I'm not rewriting it in
+# python to run on Windows...). Note that MTE stack is an ABI break, so we
+# expect it to crash under this parsing logic.
+
+# RUN: llvm-mc --filetype=obj -triple=aarch64-linux-none-gnu %s -o %t.o
+# RUN: ld.lld --memtag-mode=async --memtag-heap %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,HEAP-ASYNC-NOTE
+
+# RUN: ld.lld --memtag-mode=sync --memtag-heap %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,HEAP-SYNC-NOTE
+
+# RUN: ld.lld --memtag-mode=async --memtag-stack %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,STACK-ASYNC
+
+# RUN: ld.lld --memtag-mode=sync --memtag-stack %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,STACK-SYNC
+
+# RUN: ld.lld --memtag-mode=async --memtag-heap --memtag-stack %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,BOTH-ASYNC
+
+# RUN: ld.lld --memtag-mode=sync --memtag-heap --memtag-stack %t.o -o %t
+# RUN: llvm-readelf -n %t | \
+# RUN:    FileCheck %s --check-prefixes=NOTE,BOTH-SYNC
+
+# NOTE: .note.android.memtag
+# NOTE-NEXT: Owner
+# TODO(hctim): Update llvm-readelf to understand this note type.
+# NOTE-NEXT: Android  0x00000004  Unknown note type: (0x00000004)
+
+# The next few lines are an ABI enforcement for Android 11 and 12. If you're
+# compiling with just heap MTE (i.e just --memtag-mode), then these lines MUST
+# be unchanging.
+# HEAP-ASYNC-NOTE-NEXT: description data: 05 00 00 00
+# HEAP-SYNC-NOTE-NEXT: description data: 06 00 00 00
+
+# Stack MTE is, as of Android 12, unimplemented. However, we pre-emptively emit
+# a bit that signifies to the dynamic loader to map the primary and thread
+# stacks as PROT_MTE, in preparation for the bionic support.
+# STACK-ASYNC-NEXT: description data: 09 00 00 00
+# STACK-SYNC-NEXT: description data: 0a 00 00 00
+
+# Stack MTE is, as of Android 12, unimplemented. However, we pre-emptively emit
+# a bit that signifies to the dynamic loader to map the primary and thread
+# stacks as PROT_MTE, in preparation for the bionic support.
+# BOTH-ASYNC-NEXT: description data: 0d 00 00 00
+# BOTH-SYNC-NEXT: description data: 0e 00 00 00
+
+# RUN: not ld.lld --memtag-stack 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=MISSING-MODE
+# RUN: not ld.lld --memtag-heap 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=MISSING-MODE
+
+# MISSING-MODE:      When using --memtag-stack or --memtag-heap,
+# MISSING-MODE-SAME: a --memtag-mode value is required.
+
+# RUN: not ld.lld --memtag-mode=asymm 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=BAD-MODE
+# BAD-MODE: --memtag-mode value of "asymm" invalid
+
+# RUN: not ld.lld --memtag-mode=async 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=MISSING-STACK-OR-HEAP
+# MISSING-STACK-OR-HEAP:      When using --memtag-mode, at least one of
+# MISSING-STACK-OR-HEAP-SAME: --memtag-heap or --memtag-stack is required.
+
+.globl _start
+_start:
+  ret
Index: lld/ELF/Writer.cpp
===================================================================
--- lld/ELF/Writer.cpp
+++ lld/ELF/Writer.cpp
@@ -362,6 +362,13 @@
     part.dynSymTab =
         std::make_unique<SymbolTableSection<ELFT>>(*part.dynStrTab);
     part.dynamic = std::make_unique<DynamicSection<ELFT>>();
+
+    if (config->emachine == EM_AARCH64 &&
+        config->memtagMode != ELF::NT_MEMTAG_LEVEL_DEFAULT) {
+      part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>();
+      add(*part.memtagAndroidNote);
+    }
+
     if (config->androidPackDynRelocs)
       part.relaDyn =
           std::make_unique<AndroidPackedRelocationSection<ELFT>>(relaDynName);
Index: lld/ELF/SyntheticSections.h
===================================================================
--- lld/ELF/SyntheticSections.h
+++ lld/ELF/SyntheticSections.h
@@ -1188,6 +1188,15 @@
   void writeTo(uint8_t *buf) override;
 };
 
+class MemtagAndroidNote : public SyntheticSection {
+public:
+  MemtagAndroidNote()
+      : SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE,
+                         /* alignment=*/4, ".note.android.memtag") {}
+  void writeTo(uint8_t *buf) override;
+  size_t getSize() const override;
+};
+
 InputSection *createInterpSection();
 MergeInputSection *createCommentSection();
 template <class ELFT> void splitSections();
@@ -1218,6 +1227,7 @@
   std::unique_ptr<EhFrameSection> ehFrame;
   std::unique_ptr<GnuHashTableSection> gnuHashTab;
   std::unique_ptr<HashTableSection> hashTab;
+  std::unique_ptr<MemtagAndroidNote> memtagAndroidNote;
   std::unique_ptr<RelocationBaseSection> relaDyn;
   std::unique_ptr<RelrBaseSection> relrDyn;
   std::unique_ptr<VersionDefinitionSection> verDef;
Index: lld/ELF/SyntheticSections.cpp
===================================================================
--- lld/ELF/SyntheticSections.cpp
+++ lld/ELF/SyntheticSections.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Support/Compression.h"
@@ -3838,6 +3839,36 @@
   symTabShndx.reset();
 }
 
+constexpr char kMemtagAndroidNoteName[] = "Android";
+void MemtagAndroidNote::writeTo(uint8_t *buf) {
+  assert(sizeof(kMemtagAndroidNoteName) == 8); // ABI check for Android 11 & 12.
+  assert((config->memtagStack || config->memtagHeap) &&
+         "Should only be synthesizing a note if heap || stack is enabled.");
+
+  write32(buf, sizeof(kMemtagAndroidNoteName));        // nhdr.n_namesz
+  write32(buf + 4, sizeof(uint32_t));                  // nhdr.n_descsz
+  write32(buf + 8, llvm::ELF::NT_ANDROID_TYPE_MEMTAG); // nhdr.n_type
+  memcpy(buf + 12, kMemtagAndroidNoteName,             // name string
+         sizeof(kMemtagAndroidNoteName));
+  buf += 12 + sizeof(kMemtagAndroidNoteName);
+
+  uint32_t value = 0;
+  value |= config->memtagMode;
+  if (config->memtagHeap)
+    value |= llvm::ELF::NT_MEMTAG_HEAP;
+  // Note, MTE stack is an ABI break. Attempting to run an MTE stack-enabled
+  // binary on Android 11 or 12 will result in a checkfail in the loader.
+  if (config->memtagStack)
+    value |= llvm::ELF::NT_MEMTAG_STACK;
+  write32(buf, value); // note value
+}
+
+size_t MemtagAndroidNote::getSize() const {
+  return sizeof(llvm::ELF::Elf64_Nhdr) +
+         /* namesz=*/sizeof(kMemtagAndroidNoteName) +
+         /* descsz=*/sizeof(uint32_t);
+}
+
 InStruct elf::in;
 
 std::vector<Partition> elf::partitions;
Index: lld/ELF/Options.td
===================================================================
--- lld/ELF/Options.td
+++ lld/ELF/Options.td
@@ -719,3 +719,15 @@
     "Perform additional validation of the written dynamic relocations",
     "Do not perform additional validation of the written dynamic relocations">,
   Flags<[HelpHidden]>;
+
+// Hidden options, used by clang's -fsanitize=memtag-* options to emit an ELF
+// note to designate what kinds of memory (stack/heap) should be protected using
+// ARM's MTE on armv8.5+. A binary's desire for stack MTE can't be obtained
+// implicitly, so we have a specific bit in the note to signal to the loader to
+// remap the stack as PROT_MTE.
+defm memtag_stack: B<"memtag-stack",
+    "Instruct the dynamic loader to prepare for MTE stack instrumentation", "">;
+defm memtag_heap: B<"memtag-heap",
+    "Instruct the dynamic loader to enable MTE protection for the heap", "">;
+defm memtag_mode: Eq<"memtag-mode",
+    "Instruct the dynamic loader to start under MTE mode {async, sync, none}">;
Index: lld/ELF/Driver.cpp
===================================================================
--- lld/ELF/Driver.cpp
+++ lld/ELF/Driver.cpp
@@ -678,6 +678,28 @@
   return arg->getValue();
 }
 
+static int getMemtagMode(opt::InputArgList &args) {
+  StringRef memtagModeArg = args.getLastArgValue(OPT_memtag_mode);
+  int memtagMode = ELF::NT_MEMTAG_LEVEL_DEFAULT;
+  if (memtagModeArg == "async") {
+    memtagMode = ELF::NT_MEMTAG_LEVEL_ASYNC;
+  } else if (memtagModeArg == "sync") {
+    memtagMode = ELF::NT_MEMTAG_LEVEL_SYNC;
+  } else if (memtagModeArg == "none" || memtagModeArg.empty()) {
+    if (config->memtagStack || config->memtagHeap)
+      error("When using --memtag-stack or --memtag-heap, a --memtag-mode value "
+            "is required.");
+  } else {
+    error("--memtag-mode value of \"" + memtagModeArg +
+          "\" invalid. Should be one of {async, sync, none}.");
+  }
+  if (memtagMode != ELF::NT_MEMTAG_LEVEL_DEFAULT &&
+      !(config->memtagHeap || config->memtagStack))
+    error("When using --memtag-mode, at least one of --memtag-heap or "
+          "--memtag-stack is required.");
+  return memtagMode;
+}
+
 static ICFLevel getICF(opt::InputArgList &args) {
   auto *arg = args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all);
   if (!arg || arg->getOption().getID() == OPT_icf_none)
@@ -1066,6 +1088,10 @@
       args.hasFlag(OPT_lto_unique_basic_block_section_names,
                    OPT_no_lto_unique_basic_block_section_names, false);
   config->mapFile = args.getLastArgValue(OPT_Map);
+  config->memtagHeap = args.hasFlag(OPT_memtag_heap, OPT_no_memtag_heap, false);
+  config->memtagStack =
+      args.hasFlag(OPT_memtag_stack, OPT_no_memtag_stack, false);
+  config->memtagMode = getMemtagMode(args);
   config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0);
   config->mergeArmExidx =
       args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
Index: lld/ELF/Config.h
===================================================================
--- lld/ELF/Config.h
+++ lld/ELF/Config.h
@@ -341,6 +341,18 @@
 
   // 4 for ELF32, 8 for ELF64.
   int wordsize;
+
+  // Mode of MTE to write to the ELF note. Should be one of NT_MEMTAG_ASYNC (for
+  // async), NT_MEMTAG_SYNC (for sync), or NT_MEMTAG_DEFAULT (for none). If
+  // async or sync is enabled, write the ELF note specifying the default MTE
+  // mode.
+  int memtagMode;
+  // Signal to the dynamic loader to enable heap MTE.
+  bool memtagHeap;
+  // Signal to the dynamic loader that this binary expects stack MTE. Generally,
+  // this means to map the primary and thread stacks as PROT_MTE. Note: This is
+  // not supported on Android 11 & 12.
+  bool memtagStack;
 };
 
 // The only instance of Configuration struct.
Index: clang/test/Lexer/has_feature_memtag_stack.cpp
===================================================================
--- /dev/null
+++ clang/test/Lexer/has_feature_memtag_stack.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -E -fsanitize=memtag-stack %s -o - | FileCheck --check-prefix=CHECK-MEMTAG %s
+// RUN: %clang     -E -fsanitize=memtag --target=aarch64-unknown-linux -march=armv8a+memtag %s -o - \
+// RUN:     | FileCheck --check-prefix=CHECK-MEMTAG %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-MEMTAG %s
+
+#if __has_feature(memtag_stack)
+int MemTagSanitizerEnabled();
+#else
+int MemTagSanitizerDisabled();
+#endif
+
+// CHECK-MEMTAG: MemTagSanitizerEnabled
+// CHECK-NO-MEMTAG: MemTagSanitizerDisabled
Index: clang/test/Lexer/has_feature_memtag_sanitizer.cpp
===================================================================
--- 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
Index: clang/test/Lexer/has_feature_memtag_heap.cpp
===================================================================
--- /dev/null
+++ clang/test/Lexer/has_feature_memtag_heap.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -E -fsanitize=memtag-heap %s -o - | FileCheck --check-prefix=CHECK-MEMTAG %s
+// RUN: %clang     -E -fsanitize=memtag --target=aarch64-unknown-linux -march=armv8a+memtag %s -o - \
+// RUN:     | FileCheck --check-prefix=CHECK-MEMTAG %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-MEMTAG %s
+
+#if __has_feature(memtag_heap)
+int MemTagSanitizerEnabled();
+#else
+int MemTagSanitizerDisabled();
+#endif
+
+// CHECK-MEMTAG: MemTagSanitizerEnabled
+// CHECK-NO-MEMTAG: MemTagSanitizerDisabled
Index: clang/test/Driver/memtag.c
===================================================================
--- /dev/null
+++ clang/test/Driver/memtag.c
@@ -1,20 +0,0 @@
-// RUN: %clang     -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -mllvm -stack-safety-print=1 %s -S -o - 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SAFETY
-// RUN: %clang -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -mllvm -stack-safety-print=1 %s -S -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SAFETY
-// RUN: %clang -O2 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -mllvm -stack-safety-print=1 %s -S -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SAFETY
-// RUN: %clang -O3 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -mllvm -stack-safety-print=1 %s -S -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SAFETY
-
-// REQUIRES: aarch64-registered-target
-
-int z;
-__attribute__((noinline)) void use(int *p) { *p = z; }
-int foo() {
-  int x;
-  use(&x);
-  return x;
-}
-
-// CHECK-NO-SAFETY-NOT: allocas uses
-
-// CHECK-SAFETY-LABEL: @foo
-// CHECK-SAFETY-LABEL: allocas uses:
-// CHECK-SAFETY-NEXT: [4]: [0,4)
Index: clang/test/Driver/memtag-ld.c
===================================================================
--- /dev/null
+++ clang/test/Driver/memtag-ld.c
@@ -0,0 +1,46 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-STACK
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag-stack %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-ASYNC,CHECK-NO-HEAP,CHECK-STACK
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag-heap %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-NO-STACK
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag -fsanitize-memtag-mode=sync %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-STACK
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag-stack -fsanitize-memtag-mode=sync %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-SYNC,CHECK-NO-HEAP,CHECK-STACK
+
+// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \
+// RUN:   -fsanitize=memtag-heap -fsanitize-memtag-mode=sync %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-SYNC,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{{.*}} "-memtag-mode=async"
+// CHECK-SYNC: ld{{.*}} "-memtag-mode=sync"
+// CHECK-HEAP: "-memtag-heap"
+// CHECK-NO-HEAP-NOT: "-memtag-heap"
+// CHECK-STACK: "-memtag-stack"
+// CHECK-NO-STACK-NOT: "-memtag-stack"
+// CHECK-INVALID-MODE: memtag-mode
+// CHECK-INVALID-MODE-SAME: expected one of: {async, sync}
+// CHECK-NONE-NOT: ld{{.*}} "-memtag
+
+void f() {}
Index: clang/test/Driver/fsanitize.c
===================================================================
--- clang/test/Driver/fsanitize.c
+++ clang/test/Driver/fsanitize.c
@@ -196,13 +196,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
@@ -822,7 +822,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
Index: clang/test/CodeGen/memtag-attr.cpp
===================================================================
--- clang/test/CodeGen/memtag-attr.cpp
+++ 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
 
+// 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
+
 int HasSanitizeMemTag() { return 1; }
-// CHECK-NO: {{Function Attrs: mustprogress noinline nounwind$}}
-// CHECK-MEMTAG: Function Attrs: mustprogress noinline nounwind sanitize_memtag
+// 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() {
   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
Index: clang/lib/Driver/ToolChains/CommonArgs.cpp
===================================================================
--- clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -972,6 +972,15 @@
   if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
     CmdArgs.push_back("--export-dynamic-symbol=__cfi_check");
 
+  if (SanArgs.hasMemTag() && TC.getTriple().isAndroid()) {
+    CmdArgs.push_back(
+        Args.MakeArgString("-memtag-mode=" + SanArgs.getMemtagMode()));
+    if (SanArgs.hasMemtagHeap())
+      CmdArgs.push_back("-memtag-heap");
+    if (SanArgs.hasMemtagStack())
+      CmdArgs.push_back("-memtag-stack");
+  }
+
   return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty();
 }
 
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ 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,
@@ -652,6 +652,17 @@
     MsanParamRetval = false;
   }
 
+  if (AllAddedKinds & SanitizerKind::MemTag) {
+    StringRef S =
+        Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "async");
+    if (S.equals("async") || S.equals("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,
@@ -1230,7 +1241,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);
 }
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -726,7 +726,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);
 
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -772,7 +772,7 @@
     Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
   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);
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ 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) &&
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ 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,15 @@
   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 { return MemtagMode; }
+
   bool requiresPIE() const;
   bool needsUnwindTables() const;
   bool needsLTO() const;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1614,6 +1614,9 @@
 def fno_sanitize_address_outline_instrumentation : Flag<["-"], "fno-sanitize-address-outline-instrumentation">,
                                                    Group<f_clang_Group>,
                                                    HelpText<"Use default code inlining logic for the address sanitizer">;
+def fsanitize_memtag_mode_EQ : Joined<["-"], "fsanitize-memtag-mode=">,
+                                        Group<f_clang_Group>,
+                                        HelpText<"Set default MTE mode to 'async' (default) or 'sync'.">;
 def fsanitize_hwaddress_experimental_aliasing
   : Flag<["-"], "fsanitize-hwaddress-experimental-aliasing">,
     Group<f_clang_Group>,
Index: clang/include/clang/Basic/Sanitizers.def
===================================================================
--- clang/include/clang/Basic/Sanitizers.def
+++ 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)
Index: clang/include/clang/Basic/Features.def
===================================================================
--- clang/include/clang/Basic/Features.def
+++ 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))
Index: clang/include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -472,7 +472,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">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to