delcypher created this revision.
delcypher added reviewers: arphaman, kubamracek, yln, aralisza, kcc, vitalybuka.
Herald added subscribers: dexonsmith, dang.
Herald added a reviewer: jansvoboda11.
delcypher requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The new `-fsanitize-address-destructor-kind=` option allows control over how 
module
destructors are emitted by ASan.

The new option is consumed by both the driver and the frontend and is 
propagated into
codegen options by the frontend.

Both the legacy and new pass manager code have been updated to consume the new 
option
from the codegen options.

It would be nice if the new utility functions (`AsanDtorKindToString` and
`AsanDtorKindFromString`) could live in LLVM instead of Clang so they could be
consumed by other language frontends. Unfortunately that doesn't work because
the clang driver doesn't link against the LLVM instrumentation library.

rdar://71609176


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96572

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Basic/Sanitizers.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/SanitizerArgs.h
  clang/lib/Basic/Sanitizers.cpp
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/SanitizerArgs.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/asan-destructor-kind.cpp
  clang/test/Driver/fsanitize-address-destructor-kind.c

Index: clang/test/Driver/fsanitize-address-destructor-kind.c
===================================================================
--- /dev/null
+++ clang/test/Driver/fsanitize-address-destructor-kind.c
@@ -0,0 +1,20 @@
+// Option should not be passed to the frontend by default.
+// RUN: %clang -target x86_64-apple-macosx10.15-gnu -fsanitize=address %s \
+// RUN:   -### 2>&1 | \
+// RUN:   FileCheck %s
+// CHECK-NOT: -fsanitize-address-destructor-kind
+
+// RUN: %clang -target x86_64-apple-macosx10.15-gnu -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=none %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-NONE-ARG %s
+// CHECK-NONE-ARG: "-fsanitize-address-destructor-kind=none"
+
+// RUN: %clang -target x86_64-apple-macosx10.15-gnu -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=global %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-GLOBAL-ARG %s
+// CHECK-GLOBAL-ARG: "-fsanitize-address-destructor-kind=global"
+
+// RUN: %clang -target x86_64-apple-macosx10.15-gnu -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=bad_arg %s -### 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-INVALID-ARG %s
+// CHECK-INVALID-ARG: error: unsupported argument 'bad_arg' to option 'fsanitize-address-destructor-kind='
Index: clang/test/CodeGen/asan-destructor-kind.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/asan-destructor-kind.cpp
@@ -0,0 +1,49 @@
+// Frontend rejects invalid option
+// RUN: not %clang_cc1 -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=bad_arg -emit-llvm -o - \
+// RUN:   -triple x86_64-apple-macosx10.15 %s 2>&1 | \
+// RUN:   FileCheck %s --check-prefixes=CHECK-BAD-ARG
+// CHECK-BAD-ARG: unsupported argument 'bad_arg' to option 'fsanitize-address-destructor-kind='
+
+// Default is global dtor
+// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - -triple x86_64-apple-macosx10.15 \
+// RUN:   -fno-legacy-pass-manager %s \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-GLOBAL-DTOR
+//
+// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - -triple x86_64-apple-macosx10.15 \
+// RUN:   -flegacy-pass-manager %s \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-GLOBAL-DTOR
+
+// Explictly ask for global dtor
+// RUN: %clang_cc1 -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=global -emit-llvm -o - \
+// RUN:   -triple x86_64-apple-macosx10.15 -fno-legacy-pass-manager %s | \
+// RUN:   FileCheck %s --check-prefixes=CHECK-GLOBAL-DTOR
+//
+// RUN: %clang_cc1 -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=global -emit-llvm -o - \
+// RUN:   -triple x86_64-apple-macosx10.15 -flegacy-pass-manager %s | \
+// RUN:   FileCheck %s --check-prefixes=CHECK-GLOBAL-DTOR
+
+// CHECK-GLOBAL-DTOR: llvm.global_dtor{{.+}}asan.module_dtor
+// CHECK-GLOBAL-DTOR: define internal void @asan.module_dtor
+
+// Explictly ask for no dtors
+// RUN: %clang_cc1 -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=none -emit-llvm -o - \
+// RUN:   -triple x86_64-apple-macosx10.15 -fno-legacy-pass-manager %s | \
+// RUN:   FileCheck %s --check-prefixes=CHECK-NONE-DTOR
+//
+// RUN: %clang_cc1 -fsanitize=address \
+// RUN:   -fsanitize-address-destructor-kind=none -emit-llvm -o - \
+// RUN:   -triple x86_64-apple-macosx10.15 -flegacy-pass-manager %s | \
+// RUN:   FileCheck %s --check-prefixes=CHECK-NONE-DTOR
+
+int global;
+
+int main() {
+  return global;
+}
+
+// CHECK-NONE-DTOR-NOT: llvm.global_dtor{{.+}}asan.module_dtor
+// CHECK-NONE-DTOR-NOT: define internal void @asan.module_dtor
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1511,6 +1511,19 @@
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
+  if (LangOptsRef.Sanitize.has(SanitizerKind::Address)) {
+    if (Arg *A =
+            Args.getLastArg(options::OPT_sanitize_address_destructor_kind_EQ)) {
+      auto destructorKind = AsanDtorKindFromString(A->getValue());
+      if (destructorKind == llvm::AsanDtorKind::Invalid) {
+        Diags.Report(clang::diag::err_drv_unsupported_option_argument)
+            << A->getOption().getName() << A->getValue();
+      } else {
+        Opts.setSanitizeAddressDtorKind(destructorKind);
+      }
+    }
+  }
+
   return Success;
 }
 
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -825,6 +825,16 @@
       AsanInvalidPointerSub = true;
     }
 
+    if (const auto *Arg =
+            Args.getLastArg(options::OPT_sanitize_address_destructor_kind_EQ)) {
+      auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue());
+      if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid) {
+        TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
+            << Arg->getOption().getName() << Arg->getValue();
+      }
+      AsanDtorKind = parsedAsanDtorKind;
+    }
+
   } else {
     AsanUseAfterScope = false;
     // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address.
@@ -1074,6 +1084,13 @@
     CmdArgs.push_back("-asan-detect-invalid-pointer-sub");
   }
 
+  // Only pass the option to the frontend if the user requested,
+  // otherwise the frontend will just use the codegen default.
+  if (AsanDtorKind != llvm::AsanDtorKind::Invalid) {
+    CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-destructor-kind=" +
+                                         AsanDtorKindToString(AsanDtorKind)));
+  }
+
   if (!HwasanAbi.empty()) {
     CmdArgs.push_back("-default-function-attr");
     CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi));
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -286,10 +286,12 @@
   bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope;
   bool UseOdrIndicator = CGOpts.SanitizeAddressUseOdrIndicator;
   bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
+  llvm::AsanDtorKind DestructorKind = CGOpts.getSanitizeAddressDtorKind();
   PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
                                             UseAfterScope));
   PM.add(createModuleAddressSanitizerLegacyPassPass(
-      /*CompileKernel*/ false, Recover, UseGlobalsGC, UseOdrIndicator));
+      /*CompileKernel*/ false, Recover, UseGlobalsGC, UseOdrIndicator,
+      DestructorKind));
 }
 
 static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
@@ -1287,15 +1289,17 @@
         bool UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope;
         bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
         bool UseOdrIndicator = CodeGenOpts.SanitizeAddressUseOdrIndicator;
+        llvm::AsanDtorKind DestructorKind =
+            CodeGenOpts.getSanitizeAddressDtorKind();
         PB.registerOptimizerLastEPCallback(
             [CompileKernel, Recover, UseAfterScope, ModuleUseAfterScope,
-             UseOdrIndicator](ModulePassManager &MPM,
-                              PassBuilder::OptimizationLevel Level) {
+             UseOdrIndicator, DestructorKind](
+                ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
               MPM.addPass(
                   RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
-              MPM.addPass(ModuleAddressSanitizerPass(CompileKernel, Recover,
-                                                     ModuleUseAfterScope,
-                                                     UseOdrIndicator));
+              MPM.addPass(ModuleAddressSanitizerPass(
+                  CompileKernel, Recover, ModuleUseAfterScope, UseOdrIndicator,
+                  DestructorKind));
               MPM.addPass(createModuleToFunctionPassAdaptor(
                   AddressSanitizerPass(CompileKernel, Recover, UseAfterScope)));
             });
Index: clang/lib/Basic/Sanitizers.cpp
===================================================================
--- clang/lib/Basic/Sanitizers.cpp
+++ clang/lib/Basic/Sanitizers.cpp
@@ -51,4 +51,23 @@
 llvm::hash_code hash_value(const clang::SanitizerMask &Arg) {
   return Arg.hash_value();
 }
+
+StringRef AsanDtorKindToString(llvm::AsanDtorKind kind) {
+  switch (kind) {
+  case llvm::AsanDtorKind::None:
+    return "none";
+  case llvm::AsanDtorKind::Global:
+    return "global";
+  case llvm::AsanDtorKind::Invalid:
+    return "invalid";
+  }
+}
+
+llvm::AsanDtorKind AsanDtorKindFromString(StringRef kindStr) {
+  return llvm::StringSwitch<llvm::AsanDtorKind>(kindStr)
+      .Case("none", llvm::AsanDtorKind::None)
+      .Case("global", llvm::AsanDtorKind::Global)
+      .Default(llvm::AsanDtorKind::Invalid);
+}
+
 } // namespace clang
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ clang/include/clang/Driver/SanitizerArgs.h
@@ -43,6 +43,7 @@
   bool AsanUseOdrIndicator = false;
   bool AsanInvalidPointerCmp = false;
   bool AsanInvalidPointerSub = false;
+  llvm::AsanDtorKind AsanDtorKind = llvm::AsanDtorKind::Invalid;
   std::string HwasanAbi;
   bool LinkRuntimes = true;
   bool LinkCXXRuntimes = false;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1481,6 +1481,11 @@
             " reports in partially sanitized programs at the cost of an increase in binary size">,
   NegFlag<SetFalse, [], "Disable ODR indicator globals">>,
   Group<f_clang_Group>;
+def sanitize_address_destructor_kind_EQ : Joined<["-"], "fsanitize-address-destructor-kind=">,
+  MetaVarName<"<kind>">,
+  Flags<[CC1Option]>,
+  HelpText<"Set destructor type used in ASan instrumentation">,
+  Group<f_clang_Group>;
 // Note: This flag was introduced when it was necessary to distinguish between
 //       ABI for correct codegen.  This is no longer needed, but the flag is
 //       not removed since targeting either ABI will behave the same.
Index: clang/include/clang/Basic/Sanitizers.h
===================================================================
--- clang/include/clang/Basic/Sanitizers.h
+++ clang/include/clang/Basic/Sanitizers.h
@@ -17,6 +17,7 @@
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
 #include <cassert>
 #include <cstdint>
 
@@ -189,6 +190,11 @@
          SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
 }
 
+StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
+
+llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
+
+
 } // namespace clang
 
 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -20,6 +20,7 @@
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Regex.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
 #include <map>
 #include <memory>
 #include <string>
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -214,6 +214,9 @@
 CODEGENOPT(SanitizeAddressUseOdrIndicator, 1, 0) ///< Enable ODR indicator globals
 CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
                                              ///< MemorySanitizer
+ENUM_CODEGENOPT(SanitizeAddressDtorKind, llvm::AsanDtorKind, 2,
+                llvm::AsanDtorKind::Global)  ///< Set how ASan global
+                                             ///< destructors are emitted.
 CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
                                              ///< in MemorySanitizer
 CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to