kda updated this revision to Diff 335362.
kda added a comment.

I think this patch is near completion.
But the new code generated for the 'Always' case is definitely wrong.
I could use some coaching.  I will eventually figure it out, but an interactive 
session would probably help me along.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D99630

Files:
  clang/docs/AddressSanitizer.rst
  clang/docs/ClangCommandLineReference.rst
  clang/include/clang/Basic/CodeGenOptions.def
  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
  compiler-rt/lib/asan/asan_fake_stack.cpp
  compiler-rt/lib/asan/asan_interface.inc
  compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp
  llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h
  llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
  llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -29,6 +29,7 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/BinaryFormat/MachO.h"
+#include "llvm/CodeGen/CodeGenPassBuilder.h"
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/BasicBlock.h"
@@ -72,6 +73,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Instrumentation.h"
 #include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
+#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
 #include "llvm/Transforms/Utils/ASanStackFrameLayout.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Transforms/Utils/Local.h"
@@ -152,6 +154,8 @@
 const char kAsanHandleNoReturnName[] = "__asan_handle_no_return";
 static const int kMaxAsanStackMallocSizeClass = 10;
 const char kAsanStackMallocNameTemplate[] = "__asan_stack_malloc_";
+const char kAsanStackFlaglessMallocNameTemplate[] =
+    "__asan_stack_flagless_malloc_";
 const char kAsanStackFreeNameTemplate[] = "__asan_stack_free_";
 const char kAsanGenPrefix[] = "___asan_gen_";
 const char kODRGenPrefix[] = "__odr_asan_gen_";
@@ -597,13 +601,17 @@
 
 /// AddressSanitizer: instrument the code in module to find memory bugs.
 struct AddressSanitizer {
-  AddressSanitizer(Module &M, const GlobalsMetadata *GlobalsMD,
-                   bool CompileKernel = false, bool Recover = false,
-                   bool UseAfterScope = false)
+  AddressSanitizer(
+      Module &M, const GlobalsMetadata *GlobalsMD, bool CompileKernel = false,
+      bool Recover = false, bool UseAfterScope = false,
+      llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+          llvm::AsanDetectStackUseAfterReturnMode::Never)
       : CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan
                                                             : CompileKernel),
         Recover(ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover),
-        UseAfterScope(UseAfterScope || ClUseAfterScope), GlobalsMD(*GlobalsMD) {
+        UseAfterScope(UseAfterScope || ClUseAfterScope),
+        DetectStackUseAfterReturnMode(DetectStackUseAfterReturnMode),
+        GlobalsMD(*GlobalsMD) {
     C = &(M.getContext());
     LongSize = M.getDataLayout().getPointerSizeInBits();
     IntptrTy = Type::getIntNTy(*C, LongSize);
@@ -689,6 +697,7 @@
   bool CompileKernel;
   bool Recover;
   bool UseAfterScope;
+  llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode;
   Type *IntptrTy;
   ShadowMapping Mapping;
   FunctionCallee AsanHandleNoReturnFunc;
@@ -713,11 +722,14 @@
 public:
   static char ID;
 
-  explicit AddressSanitizerLegacyPass(bool CompileKernel = false,
-                                      bool Recover = false,
-                                      bool UseAfterScope = false)
+  explicit AddressSanitizerLegacyPass(
+      bool CompileKernel = false, bool Recover = false,
+      bool UseAfterScope = false,
+      llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+          llvm::AsanDetectStackUseAfterReturnMode::Never)
       : FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover),
-        UseAfterScope(UseAfterScope) {
+        UseAfterScope(UseAfterScope),
+        DetectStackUseAfterReturnMode(DetectStackUseAfterReturnMode) {
     initializeAddressSanitizerLegacyPassPass(*PassRegistry::getPassRegistry());
   }
 
@@ -736,7 +748,7 @@
     const TargetLibraryInfo *TLI =
         &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
     AddressSanitizer ASan(*F.getParent(), &GlobalsMD, CompileKernel, Recover,
-                          UseAfterScope);
+                          UseAfterScope, DetectStackUseAfterReturnMode);
     return ASan.instrumentFunction(F, TLI);
   }
 
@@ -744,6 +756,7 @@
   bool CompileKernel;
   bool Recover;
   bool UseAfterScope;
+  llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode;
 };
 
 class ModuleAddressSanitizer {
@@ -1182,10 +1195,12 @@
   return GlobalsMetadata(M);
 }
 
-AddressSanitizerPass::AddressSanitizerPass(bool CompileKernel, bool Recover,
-                                           bool UseAfterScope)
+AddressSanitizerPass::AddressSanitizerPass(
+    bool CompileKernel, bool Recover, bool UseAfterScope,
+    llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode)
     : CompileKernel(CompileKernel), Recover(Recover),
-      UseAfterScope(UseAfterScope) {}
+      UseAfterScope(UseAfterScope),
+      DetectStackUseAfterReturnMode(DetectStackUseAfterReturnMode) {}
 
 PreservedAnalyses AddressSanitizerPass::run(Function &F,
                                             AnalysisManager<Function> &AM) {
@@ -1193,7 +1208,8 @@
   Module &M = *F.getParent();
   if (auto *R = MAMProxy.getCachedResult<ASanGlobalsMetadataAnalysis>(M)) {
     const TargetLibraryInfo *TLI = &AM.getResult<TargetLibraryAnalysis>(F);
-    AddressSanitizer Sanitizer(M, R, CompileKernel, Recover, UseAfterScope);
+    AddressSanitizer Sanitizer(M, R, CompileKernel, Recover, UseAfterScope,
+                               DetectStackUseAfterReturnMode);
     if (Sanitizer.instrumentFunction(F, TLI))
       return PreservedAnalyses::none();
     return PreservedAnalyses::all();
@@ -1240,11 +1256,12 @@
     "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
     false)
 
-FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel,
-                                                       bool Recover,
-                                                       bool UseAfterScope) {
+FunctionPass *llvm::createAddressSanitizerFunctionPass(
+    bool CompileKernel, bool Recover, bool UseAfterScope,
+    llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode) {
   assert(!CompileKernel || Recover);
-  return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope);
+  return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope,
+                                        DetectStackUseAfterReturnMode);
 }
 
 char ModuleAddressSanitizerLegacyPass::ID = 0;
@@ -2853,13 +2870,33 @@
 
 void FunctionStackPoisoner::initializeCallbacks(Module &M) {
   IRBuilder<> IRB(*C);
-  for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
-    std::string Suffix = itostr(i);
-    AsanStackMallocFunc[i] = M.getOrInsertFunction(
-        kAsanStackMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
-    AsanStackFreeFunc[i] =
-        M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
-                              IRB.getVoidTy(), IntptrTy, IntptrTy);
+  switch (ASan.DetectStackUseAfterReturnMode) {
+  case llvm::AsanDetectStackUseAfterReturnMode::Always:
+    for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
+      std::string Suffix = itostr(i);
+      AsanStackMallocFunc[i] = M.getOrInsertFunction(
+          kAsanStackFlaglessMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
+      AsanStackFreeFunc[i] =
+          M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
+                                IRB.getVoidTy(), IntptrTy, IntptrTy);
+    }
+    break;
+  case llvm::AsanDetectStackUseAfterReturnMode::Runtime:
+    for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
+      std::string Suffix = itostr(i);
+      AsanStackMallocFunc[i] = M.getOrInsertFunction(
+          kAsanStackMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
+      AsanStackFreeFunc[i] =
+          M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
+                                IRB.getVoidTy(), IntptrTy, IntptrTy);
+    }
+    break;
+  case llvm::AsanDetectStackUseAfterReturnMode::Never:
+    // Do Nothing
+    break;
+  case llvm::AsanDetectStackUseAfterReturnMode::Invalid:
+    // Do Nothing
+    break;
   }
   if (ASan.UseAfterScope) {
     AsanPoisonStackMemoryFunc = M.getOrInsertFunction(
@@ -3221,6 +3258,8 @@
   //    register-relative calculation of local variable addresses.
   DoDynamicAlloca &= !HasInlineAsm && !HasReturnsTwiceCall;
   DoStackMalloc &= !HasInlineAsm && !HasReturnsTwiceCall;
+  DoStackMalloc &= ASan.DetectStackUseAfterReturnMode !=
+                   llvm::AsanDetectStackUseAfterReturnMode::Never;
 
   Value *StaticAlloca =
       DoDynamicAlloca ? nullptr : createAllocaForLayout(IRB, L, false);
@@ -3237,34 +3276,62 @@
     //     ? __asan_stack_malloc_N(LocalStackSize)
     //     : nullptr;
     // void *LocalStackBase = (FakeStack) ? FakeStack : alloca(LocalStackSize);
-    Constant *OptionDetectUseAfterReturn = F.getParent()->getOrInsertGlobal(
-        kAsanOptionDetectUseAfterReturn, IRB.getInt32Ty());
-    Value *UseAfterReturnIsEnabled = IRB.CreateICmpNE(
-        IRB.CreateLoad(IRB.getInt32Ty(), OptionDetectUseAfterReturn),
-        Constant::getNullValue(IRB.getInt32Ty()));
-    Instruction *Term =
-        SplitBlockAndInsertIfThen(UseAfterReturnIsEnabled, InsBefore, false);
-    IRBuilder<> IRBIf(Term);
     StackMallocIdx = StackMallocSizeClass(LocalStackSize);
     assert(StackMallocIdx <= kMaxAsanStackMallocSizeClass);
-    Value *FakeStackValue =
-        IRBIf.CreateCall(AsanStackMallocFunc[StackMallocIdx],
+    if (ASan.DetectStackUseAfterReturnMode ==
+        llvm::AsanDetectStackUseAfterReturnMode::Runtime) {
+      Constant *OptionDetectUseAfterReturn = F.getParent()->getOrInsertGlobal(
+          kAsanOptionDetectUseAfterReturn, IRB.getInt32Ty());
+      Value *UseAfterReturnIsEnabled = IRB.CreateICmpNE(
+          IRB.CreateLoad(IRB.getInt32Ty(), OptionDetectUseAfterReturn),
+          Constant::getNullValue(IRB.getInt32Ty()));
+      Instruction *Term =
+          SplitBlockAndInsertIfThen(UseAfterReturnIsEnabled, InsBefore, false);
+      IRBuilder<> IRBIf(Term);
+      Value *FakeStackValue =
+          IRBIf.CreateCall(AsanStackMallocFunc[StackMallocIdx],
+                           ConstantInt::get(IntptrTy, LocalStackSize));
+      IRB.SetInsertPoint(InsBefore);
+      FakeStack = createPHI(IRB, UseAfterReturnIsEnabled, FakeStackValue, Term,
+                            ConstantInt::get(IntptrTy, 0));
+
+      Value *NoFakeStack =
+          IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy));
+      Term = SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false);
+      IRBIf.SetInsertPoint(Term);
+      Value *AllocaValue = DoDynamicAlloca
+                               ? createAllocaForLayout(IRBIf, L, true)
+                               : StaticAlloca;
+
+      IRB.SetInsertPoint(InsBefore);
+      LocalStackBase =
+          createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack);
+      IRB.CreateStore(LocalStackBase, LocalStackBaseAlloca);
+      DIExprFlags |= DIExpression::DerefBefore;
+    } else {
+      // ASan.DetectStackUseAfterReturnMode ==
+      //    llvm::AsanDetectStackUseAfterReturnMode::Always
+      Value *FakeStackValue =
+          IRB.CreateCall(AsanStackMallocFunc[StackMallocIdx],
                          ConstantInt::get(IntptrTy, LocalStackSize));
-    IRB.SetInsertPoint(InsBefore);
-    FakeStack = createPHI(IRB, UseAfterReturnIsEnabled, FakeStackValue, Term,
-                          ConstantInt::get(IntptrTy, 0));
-
-    Value *NoFakeStack =
-        IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy));
-    Term = SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false);
-    IRBIf.SetInsertPoint(Term);
-    Value *AllocaValue =
-        DoDynamicAlloca ? createAllocaForLayout(IRBIf, L, true) : StaticAlloca;
-
-    IRB.SetInsertPoint(InsBefore);
-    LocalStackBase = createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack);
-    IRB.CreateStore(LocalStackBase, LocalStackBaseAlloca);
-    DIExprFlags |= DIExpression::DerefBefore;
+      IRB.SetInsertPoint(InsBefore);
+      PHINode *FakeStack = IRB.CreatePHI(IntptrTy, 1);
+      FakeStack->addIncoming(FakeStackValue, InsBefore->getParent());
+
+      Value *NoFakeStack =
+          IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy));
+      Instruction *Term =
+          SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false);
+      IRB.SetInsertPoint(Term);
+      Value *AllocaValue =
+          DoDynamicAlloca ? createAllocaForLayout(IRB, L, true) : StaticAlloca;
+
+      IRB.SetInsertPoint(InsBefore);
+      LocalStackBase =
+          createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack);
+      IRB.CreateStore(LocalStackBase, LocalStackBaseAlloca);
+      DIExprFlags |= DIExpression::DerefBefore;
+    }
   } else {
     // void *FakeStack = nullptr;
     // void *LocalStackBase = alloca(LocalStackSize);
Index: llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
===================================================================
--- llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
+++ llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
@@ -20,5 +20,16 @@
   Invalid, ///< Not a valid destructor Kind.
   // TODO(dliew): Add more more kinds.
 };
+
+/// Modes of ASan detect stack use after return
+enum class AsanDetectStackUseAfterReturnMode {
+  Always,  ///< Always detect stack use after return.
+  Runtime, ///< Detect stack use after return if runtime flag is enabled
+           ///< (ASAN_OPTIONS=detect_stack_use_after_return=1)
+  Never,   ///< Never detect stack use after return.
+  Invalid, ///< Not a valid detect mode.
+};
+
 } // namespace llvm
+
 #endif
Index: llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h
===================================================================
--- llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h
+++ llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h
@@ -18,6 +18,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
+#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 
 namespace llvm {
 
@@ -99,9 +100,11 @@
 /// surrounding requested memory to be checked for invalid accesses.
 class AddressSanitizerPass : public PassInfoMixin<AddressSanitizerPass> {
 public:
-  explicit AddressSanitizerPass(bool CompileKernel = false,
-                                bool Recover = false,
-                                bool UseAfterScope = false);
+  explicit AddressSanitizerPass(
+      bool CompileKernel = false, bool Recover = false,
+      bool UseAfterScope = false,
+      llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+          llvm::AsanDetectStackUseAfterReturnMode::Never);
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
   static bool isRequired() { return true; }
 
@@ -109,6 +112,7 @@
   bool CompileKernel;
   bool Recover;
   bool UseAfterScope;
+  llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode;
 };
 
 /// Public interface to the address sanitizer module pass for instrumenting code
@@ -135,9 +139,11 @@
 };
 
 // Insert AddressSanitizer (address sanity checking) instrumentation
-FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
-                                                 bool Recover = false,
-                                                 bool UseAfterScope = false);
+FunctionPass *createAddressSanitizerFunctionPass(
+    bool CompileKernel = false, bool Recover = false,
+    bool UseAfterScope = false,
+    llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+        llvm::AsanDetectStackUseAfterReturnMode::Never);
 ModulePass *createModuleAddressSanitizerLegacyPassPass(
     bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true,
     bool UseOdrIndicator = true,
Index: compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp
===================================================================
--- compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp
+++ compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp
@@ -3,6 +3,12 @@
 // RUN: %clangxx_asan  -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan  -O3 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
 // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
+// run: %clangxx_asan -fsanitize-address-detect-stack-use-after-return=always -O1 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
+// run: %env_asan_opts=detect_stack_use_after_return=0 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -fsanitize-address-detect-stack-use-after-return=runtime -O1 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
+// RUN: %clangxx_asan -fsanitize-address-detect-stack-use-after-return=never -O1 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 %run %t
+// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
 // Regression test for a CHECK failure with small stack size and large frame.
 // RUN: %clangxx_asan  -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
 //
@@ -89,7 +95,7 @@
       fprintf(stderr, "pthread_attr_setstacksize returned %d\n", ret);
       abort();
     }
-    
+
     size_t stacksize_check;
     ret = pthread_attr_getstacksize(&attr, &stacksize_check);
     if (ret != 0) {
@@ -100,7 +106,7 @@
     if (stacksize_check != desired_stack_size) {
       fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n",
               (int)desired_stack_size, (int)stacksize_check);
-      abort(); 
+      abort();
     }
   }
   pthread_t t;
Index: compiler-rt/lib/asan/asan_interface.inc
===================================================================
--- compiler-rt/lib/asan/asan_interface.inc
+++ compiler-rt/lib/asan/asan_interface.inc
@@ -134,6 +134,17 @@
 INTERFACE_FUNCTION(__asan_stack_malloc_8)
 INTERFACE_FUNCTION(__asan_stack_malloc_9)
 INTERFACE_FUNCTION(__asan_stack_malloc_10)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_flagless_malloc_10)
 INTERFACE_FUNCTION(__asan_store1)
 INTERFACE_FUNCTION(__asan_store2)
 INTERFACE_FUNCTION(__asan_store4)
Index: compiler-rt/lib/asan/asan_fake_stack.cpp
===================================================================
--- compiler-rt/lib/asan/asan_fake_stack.cpp
+++ compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -198,6 +198,12 @@
   return GetFakeStack();
 }
 
+static FakeStack *GetFakeStackFastFlagless() {
+  if (FakeStack *fs = GetTLSFakeStack())
+    return fs;
+  return GetFakeStack();
+}
+
 ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
   FakeStack *fs = GetFakeStackFast();
   if (!fs) return 0;
@@ -210,6 +216,20 @@
   return ptr;
 }
 
+ALWAYS_INLINE uptr OnMallocFlagless(uptr class_id, uptr size) {
+  FakeStack *fs = GetFakeStackFastFlagless();
+  if (!fs)
+    return 0;
+  uptr local_stack;
+  uptr real_stack = reinterpret_cast<uptr>(&local_stack);
+  FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
+  if (!ff)
+    return 0;  // Out of fake stack.
+  uptr ptr = reinterpret_cast<uptr>(ff);
+  SetShadow(ptr, size, class_id, 0);
+  return ptr;
+}
+
 ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
   FakeStack::Deallocate(ptr, class_id);
   SetShadow(ptr, size, class_id, kMagic8);
@@ -240,10 +260,34 @@
 DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
 DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
 DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
+
+using namespace __asan;
+#define DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(class_id) \
+  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr              \
+      __asan_stack_flagless_malloc_##class_id(uptr size) {   \
+    return OnMallocFlagless(class_id, size);                 \
+  }
+
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(0)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(1)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(2)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(3)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(4)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(5)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(6)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(7)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(8)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(9)
+DEFINE_STACK_FLAGLESS_MALLOC_WITH_CLASS_ID(10)
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_get_current_fake_stack_flagless() {
+  return GetFakeStackFastFlagless();
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE
 void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
                                    void **end) {
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -841,6 +841,19 @@
       AsanDtorKind = parsedAsanDtorKind;
     }
 
+    if (const auto *Arg = Args.getLastArg(
+            options::OPT_sanitize_address_detect_stack_use_after_return_EQ)) {
+      auto parsedAsanDetectStackUseAfterReturnMode =
+          AsanDetectStackUseAfterReturnModeFromString(Arg->getValue());
+      if (parsedAsanDetectStackUseAfterReturnMode ==
+          llvm::AsanDetectStackUseAfterReturnMode::Invalid) {
+        TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
+            << Arg->getOption().getName() << Arg->getValue();
+      }
+      AsanDetectStackUseAfterReturnMode =
+          parsedAsanDetectStackUseAfterReturnMode;
+    }
+
   } else {
     AsanUseAfterScope = false;
     // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address.
@@ -1102,6 +1115,16 @@
                                          AsanDtorKindToString(AsanDtorKind)));
   }
 
+  // Only pass the option to the frontend if the user requested,
+  // otherwise the frontend will just use the codegen default.
+  if (AsanDetectStackUseAfterReturnMode !=
+      llvm::AsanDetectStackUseAfterReturnMode::Runtime) {
+    CmdArgs.push_back(
+        Args.MakeArgString("-fsanitize-address-detect-stack-use-after-return=" +
+                           AsanDetectStackUseAfterReturnModeToString(
+                               AsanDetectStackUseAfterReturnMode)));
+  }
+
   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
@@ -65,6 +65,7 @@
 #include "llvm/Transforms/InstCombine/InstCombine.h"
 #include "llvm/Transforms/Instrumentation.h"
 #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
+#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
 #include "llvm/Transforms/Instrumentation/BoundsChecking.h"
 #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
 #include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
@@ -288,8 +289,11 @@
   bool UseOdrIndicator = CGOpts.SanitizeAddressUseOdrIndicator;
   bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
   llvm::AsanDtorKind DestructorKind = CGOpts.getSanitizeAddressDtorKind();
+  llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+      CGOpts.getSanitizeAddressDetectStackUseAfterReturnMode();
   PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
-                                            UseAfterScope));
+                                            UseAfterScope,
+                                            DetectStackUseAfterReturnMode));
   PM.add(createModuleAddressSanitizerLegacyPassPass(
       /*CompileKernel*/ false, Recover, UseGlobalsGC, UseOdrIndicator,
       DestructorKind));
@@ -298,7 +302,9 @@
 static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
                                             legacy::PassManagerBase &PM) {
   PM.add(createAddressSanitizerFunctionPass(
-      /*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false));
+      /*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false,
+      /*DetectStackUseAfterReturnMode*/
+      llvm::AsanDetectStackUseAfterReturnMode::Never));
   PM.add(createModuleAddressSanitizerLegacyPassPass(
       /*CompileKernel*/ true, /*Recover*/ true, /*UseGlobalsGC*/ true,
       /*UseOdrIndicator*/ false));
@@ -1143,12 +1149,15 @@
         bool UseOdrIndicator = CodeGenOpts.SanitizeAddressUseOdrIndicator;
         llvm::AsanDtorKind DestructorKind =
             CodeGenOpts.getSanitizeAddressDtorKind();
+        llvm::AsanDetectStackUseAfterReturnMode DetectStackUseAfterReturnMode =
+            CodeGenOpts.getSanitizeAddressDetectStackUseAfterReturnMode();
         MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
         MPM.addPass(ModuleAddressSanitizerPass(
             CompileKernel, Recover, ModuleUseAfterScope, UseOdrIndicator,
             DestructorKind));
         MPM.addPass(createModuleToFunctionPassAdaptor(
-            AddressSanitizerPass(CompileKernel, Recover, UseAfterScope)));
+            AddressSanitizerPass(CompileKernel, Recover, UseAfterScope,
+                                 DetectStackUseAfterReturnMode)));
       }
     };
     ASanPass(SanitizerKind::Address, false);
Index: clang/lib/Basic/Sanitizers.cpp
===================================================================
--- clang/lib/Basic/Sanitizers.cpp
+++ clang/lib/Basic/Sanitizers.cpp
@@ -80,4 +80,28 @@
       .Default(llvm::AsanDtorKind::Invalid);
 }
 
+StringRef AsanDetectStackUseAfterReturnModeToString(
+    llvm::AsanDetectStackUseAfterReturnMode mode) {
+  switch (mode) {
+  case llvm::AsanDetectStackUseAfterReturnMode::Always:
+    return "always";
+  case llvm::AsanDetectStackUseAfterReturnMode::Runtime:
+    return "runtime";
+  case llvm::AsanDetectStackUseAfterReturnMode::Never:
+    return "never";
+  case llvm::AsanDetectStackUseAfterReturnMode::Invalid:
+    return "invalid";
+  }
+  return "invalid";
+}
+
+llvm::AsanDetectStackUseAfterReturnMode
+AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr) {
+  return llvm::StringSwitch<llvm::AsanDetectStackUseAfterReturnMode>(modeStr)
+      .Case("always", llvm::AsanDetectStackUseAfterReturnMode::Always)
+      .Case("runtime", llvm::AsanDetectStackUseAfterReturnMode::Runtime)
+      .Case("never", llvm::AsanDetectStackUseAfterReturnMode::Never)
+      .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid);
+}
+
 } // namespace clang
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ clang/include/clang/Driver/SanitizerArgs.h
@@ -44,6 +44,8 @@
   bool AsanInvalidPointerCmp = false;
   bool AsanInvalidPointerSub = false;
   llvm::AsanDtorKind AsanDtorKind = llvm::AsanDtorKind::Invalid;
+  llvm::AsanDetectStackUseAfterReturnMode AsanDetectStackUseAfterReturnMode =
+      llvm::AsanDetectStackUseAfterReturnMode::Runtime;
   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
@@ -1534,6 +1534,16 @@
       NormalizedValuesScope<"llvm::AsanDtorKind">,
       NormalizedValues<["None", "Global"]>,
       MarshallingInfoEnum<CodeGenOpts<"SanitizeAddressDtorKind">, "Global">;
+def sanitize_address_detect_stack_use_after_return_EQ
+    : Joined<["-"], "fsanitize-address-detect-stack-use-after-return=">,
+      MetaVarName<"<mode>">,
+      Flags<[CC1Option]>,
+      HelpText<"Select the enabling method of detect-stack-use-after-return in AddressSanitizer">,
+      Group<f_clang_Group>,
+      Values<"always,runtime,never">,
+      NormalizedValuesScope<"llvm::AsanDetectStackUseAfterReturnMode">,
+      NormalizedValues<["Always", "Runtime", "Never"]>,
+      MarshallingInfoEnum<CodeGenOpts<"SanitizeAddressDetectStackUseAfterReturnMode">, "Runtime">;
 // 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
@@ -198,6 +198,12 @@
 
 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
 
+StringRef AsanDetectStackUseAfterReturnModeToString(
+    llvm::AsanDetectStackUseAfterReturnMode mode);
+
+llvm::AsanDetectStackUseAfterReturnMode
+AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
+
 } // namespace clang
 
 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -222,6 +222,10 @@
 ENUM_CODEGENOPT(SanitizeAddressDtorKind, llvm::AsanDtorKind, 2,
                 llvm::AsanDtorKind::Global)  ///< Set how ASan global
                                              ///< destructors are emitted.
+ENUM_CODEGENOPT(SanitizeAddressDetectStackUseAfterReturnMode,
+                llvm::AsanDetectStackUseAfterReturnMode, 2 /* ??? */,
+                llvm::AsanDetectStackUseAfterReturnMode::Runtime
+                ) ///< Set detection mode for stack-use-after-return.
 CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
                                              ///< in MemorySanitizer
 CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI.
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -881,6 +881,15 @@
 * ``global`` - Emit module destructors that are called via a platform specific array (see `llvm.global_dtors`).
 * ``none`` - Do not emit module destructors.
 
+.. option:: -fsanitize-address-detect-stack-use-after-return=<arg>
+
+Select the enabling method of detect-stack-use-after-return in AddressSanitizer.
+
+Valid options are:
+* ``always`` - Always detect use-after-return.  (Code generated and always enabled.)
+* ``runtime`` - Detect use-after-return at runtime if enabled by runtime command line (flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
+* ``never`` - Never detect use-after-return.  (Code not generated for detection.)
+
 .. option:: -fsanitize-blacklist=<arg>
 
 Path to blacklist file for sanitizers
Index: clang/docs/AddressSanitizer.rst
===================================================================
--- clang/docs/AddressSanitizer.rst
+++ clang/docs/AddressSanitizer.rst
@@ -14,7 +14,8 @@
 
 * Out-of-bounds accesses to heap, stack and globals
 * Use-after-free
-* Use-after-return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
+* Use-after-return (clang flag `-fsanitize-address-detect-stack-use-after-return=(always|runtime|never)` default: runtime)
+  * Add runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1` to enable when compiled with `-fsanitize-address-detect-stack-use-after-return=runtime`)
 * Use-after-scope (clang flag `-fsanitize-address-use-after-scope`)
 * Double-free, invalid free
 * Memory leaks (experimental)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to