diff --git a/clang/docs/AddressSanitizer.rst b/clang/docs/AddressSanitizer.rst --- a/clang/docs/AddressSanitizer.rst +++ b/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) diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/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= + +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= Path to blacklist file for sanitizers diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/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. diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h --- a/clang/include/clang/Basic/Sanitizers.h +++ b/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 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 @@ -1534,6 +1534,16 @@ NormalizedValuesScope<"llvm::AsanDtorKind">, NormalizedValues<["None", "Global"]>, MarshallingInfoEnum, "Global">; +def sanitize_address_detect_stack_use_after_return_EQ + : Joined<["-"], "fsanitize-address-detect-stack-use-after-return=">, + MetaVarName<"">, + Flags<[CC1Option]>, + HelpText<"Select the enabling method of detect-stack-use-after-return in AddressSanitizer">, + Group, + Values<"always,runtime,never">, + NormalizedValuesScope<"llvm::AsanDetectStackUseAfterReturnMode">, + NormalizedValues<["Always", "Runtime", "Never"]>, + MarshallingInfoEnum, "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. 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 @@ -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; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp --- a/clang/lib/Basic/Sanitizers.cpp +++ b/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(modeStr) + .Case("always", llvm::AsanDetectStackUseAfterReturnMode::Always) + .Case("runtime", llvm::AsanDetectStackUseAfterReturnMode::Runtime) + .Case("never", llvm::AsanDetectStackUseAfterReturnMode::Never) + .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid); +} + } // namespace clang diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/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()); MPM.addPass(ModuleAddressSanitizerPass( CompileKernel, Recover, ModuleUseAfterScope, UseOdrIndicator, DestructorKind)); MPM.addPass(createModuleToFunctionPassAdaptor( - AddressSanitizerPass(CompileKernel, Recover, UseAfterScope))); + AddressSanitizerPass(CompileKernel, Recover, UseAfterScope, + DetectStackUseAfterReturnMode))); } }; ASanPass(SanitizerKind::Address, false); 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 @@ -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)); diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/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(&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(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) { diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc --- a/compiler-rt/lib/asan/asan_interface.inc +++ b/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) diff --git a/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp b/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp --- a/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp +++ b/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; diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h +++ b/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 { 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, diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h +++ b/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 diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/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().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 &AM) { @@ -1193,7 +1208,8 @@ Module &M = *F.getParent(); if (auto *R = MAMProxy.getCachedResult(M)) { const TargetLibraryInfo *TLI = &AM.getResult(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);