melver created this revision.
Herald added a subscriber: ormris.
Herald added a project: All.
melver requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.

Introduces the frontend flag -fexperimental-sanitize-metadata=, which
enables SanitizerBinaryMetadata instrumentation.

The first intended user of the binary metadata emitted will be a variant
of GWP-TSan [1]. The plan is to open source a stable and production
quality version of GWP-TSan. The development of which, however, requires
upstream compiler support.

[1] https://llvm.org/devmtg/2020-09/slides/Morehouse-GWP-Tsan.pdf

Until the tool has been open sourced, we mark this kind of
instrumentation as "experimental", and reserve the option to change
binary format, remove features, and similar.

Depends on D130887 <https://reviews.llvm.org/D130887>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130888

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/SanitizerArgs.h
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/SanitizerArgs.cpp
  clang/test/Driver/fsanitize-metadata.c

Index: clang/test/Driver/fsanitize-metadata.c
===================================================================
--- /dev/null
+++ clang/test/Driver/fsanitize-metadata.c
@@ -0,0 +1,22 @@
+// RUN: %clang -target x86_64-linux-gnu %s -### 2>&1 | FileCheck %s
+// CHECK-NOT: -fexperimental-sanitize-metadata
+
+// RUN: %clang -target x86_64-linux-gnu -fexperimental-sanitize-metadata=bad_arg %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-INVALID %s
+// CHECK-INVALID: error: unsupported argument 'bad_arg' to option '-fexperimental-sanitize-metadata='
+
+// RUN: %clang -target x86_64-linux-gnu -fexperimental-sanitize-metadata=covered %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-COVERED %s
+// CHECK-COVERED: "-fexperimental-sanitize-metadata-covered"
+
+// RUN: %clang -target x86_64-linux-gnu -fexperimental-sanitize-metadata=atomics %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-ATOMICS %s
+// CHECK-ATOMICS: "-fexperimental-sanitize-metadata-atomics"
+
+// RUN: %clang -target x86_64-linux-gnu \
+// RUN:   -fexperimental-sanitize-metadata=covered,atomics %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-ALL %s
+// RUN: %clang -target x86_64-linux-gnu -fexperimental-sanitize-metadata=all %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-ALL %s
+// CHECK-ALL: "-fexperimental-sanitize-metadata-covered"
+// CHECK-ALL: "-fexperimental-sanitize-metadata-atomics"
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -98,6 +98,11 @@
   CoverageTraceStores = 1 << 17,
 };
 
+enum BinaryMetadataFeature {
+  BinaryMetadataCovered = 1 << 0,
+  BinaryMetadataAtomics = 1 << 1,
+};
+
 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
 /// invalid components. Returns a SanitizerMask.
 static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
@@ -108,6 +113,11 @@
 static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
                                  bool DiagnoseErrors);
 
+/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid
+/// components. Returns OR of members of \c BinaryMetadataFeature enumeration.
+static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+                                       bool DiagnoseErrors);
+
 /// Produce an argument string from ArgList \p Args, which shows how it
 /// provides some sanitizer kind from \p Mask. For example, the argument list
 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
@@ -825,6 +835,21 @@
         DiagnoseErrors);
   }
 
+  // Parse -f(no-)?sanitize-metadata.
+  for (const auto *Arg : Args) {
+    if (Arg->getOption().matches(
+            options::OPT_fexperimental_sanitize_metadata)) {
+      Arg->claim();
+      BinaryMetadataFeatures |=
+          parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+    } else if (Arg->getOption().matches(
+                   options::OPT_fno_experimental_sanitize_metadata)) {
+      Arg->claim();
+      BinaryMetadataFeatures &=
+          ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+    }
+  }
+
   SharedRuntime =
       Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
                    TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
@@ -1086,6 +1111,17 @@
   addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=",
                         CoverageIgnorelistFiles);
 
+  // Translate available BinaryMetadataFeatures to corresponding clang-cc1
+  // flags. Does not depend on any other sanitizers.
+  const std::pair<int, std::string> BinaryMetadataFlags[] = {
+      std::make_pair(BinaryMetadataCovered, "covered"),
+      std::make_pair(BinaryMetadataAtomics, "atomics")};
+  for (const auto &F : BinaryMetadataFlags) {
+    if (BinaryMetadataFeatures & F.first)
+      CmdArgs.push_back(
+          Args.MakeArgString("-fexperimental-sanitize-metadata-" + F.second));
+  }
+
   if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
     // Instruct the code generator to embed linker directives in the object file
     // that cause the required runtime libraries to be linked.
@@ -1332,6 +1368,27 @@
   return Features;
 }
 
+int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+                                bool DiagnoseErrors) {
+  assert(
+      A->getOption().matches(options::OPT_fexperimental_sanitize_metadata) ||
+      A->getOption().matches(options::OPT_fno_experimental_sanitize_metadata));
+  int Features = 0;
+  for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+    const char *Value = A->getValue(i);
+    int F = llvm::StringSwitch<int>(Value)
+                .Case("covered", BinaryMetadataCovered)
+                .Case("atomics", BinaryMetadataAtomics)
+                .Case("all", ~0)
+                .Default(0);
+    if (F == 0 && DiagnoseErrors)
+      D.Diag(clang::diag::err_drv_unsupported_option_argument)
+          << A->getOption().getName() << Value;
+    Features |= F;
+  }
+  return Features;
+}
+
 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
                                 SanitizerMask Mask) {
   for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -73,6 +73,7 @@
 #include "llvm/Transforms/Instrumentation/MemProfiler.h"
 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
 #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
+#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
 #include "llvm/Transforms/ObjCARC.h"
 #include "llvm/Transforms/Scalar.h"
@@ -218,6 +219,14 @@
   return Opts;
 }
 
+static SanitizerBinaryMetadataOptions
+getSanitizerBinaryMetadataOptions(const CodeGenOptions &CGOpts) {
+  SanitizerBinaryMetadataOptions Opts;
+  Opts.Covered = CGOpts.SanitizeBinaryMetadataCovered;
+  Opts.Atomics = CGOpts.SanitizeBinaryMetadataAtomics;
+  return Opts;
+}
+
 // Check if ASan should use GC-friendly instrumentation for globals.
 // First of all, there is no point if -fdata-sections is off (expect for MachO,
 // where this is not a factor). Also, on ELF this feature requires an assembler
@@ -632,6 +641,11 @@
           CodeGenOpts.SanitizeCoverageIgnorelistFiles));
     }
 
+    if (CodeGenOpts.hasSanitizeBinaryMetadata()) {
+      MPM.addPass(ModuleSanitizerBinaryMetadataPass(
+          getSanitizerBinaryMetadataOptions(CodeGenOpts)));
+    }
+
     auto MSanPass = [&](SanitizerMask Mask, bool CompileKernel) {
       if (LangOpts.Sanitize.has(Mask)) {
         int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins;
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ clang/include/clang/Driver/SanitizerArgs.h
@@ -31,6 +31,7 @@
   std::vector<std::string> CoverageAllowlistFiles;
   std::vector<std::string> CoverageIgnorelistFiles;
   int CoverageFeatures = 0;
+  int BinaryMetadataFeatures = 0;
   int MsanTrackOrigins = 0;
   bool MsanUseAfterDtor = true;
   bool MsanParamRetval = false;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1683,6 +1683,12 @@
   Group<f_clang_Group>, Flags<[CoreOption, HelpHidden]>,
   Alias<fsanitize_coverage_ignorelist>,
   HelpText<"Deprecated, use -fsanitize-coverage-ignorelist= instead">;
+def fexperimental_sanitize_metadata : CommaJoined<["-"], "fexperimental-sanitize-metadata=">,
+  Group<f_clang_Group>,
+  HelpText<"Specify the type of metadata to emit for binary analysis sanitizers">;
+def fno_experimental_sanitize_metadata : CommaJoined<["-"], "fno-experimental-sanitize-metadata=">,
+  Group<f_clang_Group>, Flags<[CoreOption, NoXarchOption]>,
+  HelpText<"Disable emitting metadata for binary analysis sanitizers">;
 def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
                                         Group<f_clang_Group>,
                                         HelpText<"Enable origins tracking in MemorySanitizer">,
@@ -5493,6 +5499,14 @@
     : Flag<["-"], "fsanitize-coverage-trace-stores">,
       HelpText<"Enable tracing of stores">,
       MarshallingInfoFlag<CodeGenOpts<"SanitizeCoverageTraceStores">>;
+def fexperimental_sanitize_metadata_covered
+    : Flag<["-"], "fexperimental-sanitize-metadata-covered">,
+      HelpText<"Emit PCs for code covered with binary analysis sanitizers">,
+      MarshallingInfoFlag<CodeGenOpts<"SanitizeBinaryMetadataCovered">>;
+def fexperimental_sanitize_metadata_atomics
+    : Flag<["-"], "fexperimental-sanitize-metadata-atomics">,
+      HelpText<"Emit PCs for atomic operations used by binary analysis sanitizers">,
+      MarshallingInfoFlag<CodeGenOpts<"SanitizeBinaryMetadataAtomics">>;
 def fpatchable_function_entry_offset_EQ
     : Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"<M>">,
       HelpText<"Generate M NOPs before function entry">,
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -485,6 +485,11 @@
            SanitizeCoverageTraceCmp || SanitizeCoverageTraceLoads ||
            SanitizeCoverageTraceStores;
   }
+
+  // Check if any one of SanitizeBinaryMetadata* is enabled.
+  bool hasSanitizeBinaryMetadata() const {
+    return SanitizeBinaryMetadataCovered || SanitizeBinaryMetadataAtomics;
+  }
 };
 
 }  // end namespace clang
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -284,6 +284,8 @@
 CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing
 CODEGENOPT(SanitizeCoverageTraceLoads, 1, 0) ///< Enable tracing of loads.
 CODEGENOPT(SanitizeCoverageTraceStores, 1, 0) ///< Enable tracing of stores.
+CODEGENOPT(SanitizeBinaryMetadataCovered, 1, 0) ///< Emit PCs for covered functions.
+CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0) ///< Emit PCs for atomic operations.
 CODEGENOPT(SanitizeStats     , 1, 0) ///< Collect statistics for sanitizers.
 CODEGENOPT(SimplifyLibCalls  , 1, 1) ///< Set when -fbuiltin is enabled.
 CODEGENOPT(SoftFloat         , 1, 0) ///< -soft-float.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to