Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -642,6 +642,9 @@ def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">, Group, Flags<[CC1Option]>, HelpText<"Level of field padding for AddressSanitizer">; +def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">, + Group, Flags<[CC1Option]>, + HelpText<"Enable use-after-scope detection in AddressSanitizer">; def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group, Flags<[CoreOption]>; def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, Index: include/clang/Driver/SanitizerArgs.h =================================================================== --- include/clang/Driver/SanitizerArgs.h +++ include/clang/Driver/SanitizerArgs.h @@ -34,6 +34,7 @@ bool CfiCrossDso = false; int AsanFieldPadding = 0; bool AsanSharedRuntime = false; + bool AsanUseAfterScope = false; bool LinkCXXRuntimes = false; bool NeedPIE = false; bool Stats = false; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -124,6 +124,8 @@ CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA. CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. +CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection + ///< in AddressSanitizer CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in ///< MemorySanitizer CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -184,7 +184,7 @@ } static void addBoundsCheckingPass(const PassManagerBuilder &Builder, - legacy::PassManagerBase &PM) { + legacy::PassManagerBase &PM) { PM.add(createBoundsCheckingPass()); } @@ -210,14 +210,17 @@ static_cast(Builder); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address); - PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/false, Recover)); + bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope; + PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover, + UseAfterScope)); PM.add(createAddressSanitizerModulePass(/*CompileKernel*/false, Recover)); } static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/true, - /*Recover*/true)); + PM.add(createAddressSanitizerFunctionPass( + /*CompileKernel*/ true, + /*Recover*/ true, /*UseAfterScope*/ false)); PM.add(createAddressSanitizerModulePass(/*CompileKernel*/true, /*Recover*/true)); } Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -679,10 +679,10 @@ EmitStoreThroughLValue(RValue::get(value), lvalue, true); return; } - + if (const CXXDefaultInitExpr *DIE = dyn_cast(init)) init = DIE->getExpr(); - + // If we're emitting a value with lifetime, we have to do the // initialization *before* we leave the cleanup scopes. if (const ExprWithCleanups *ewc = dyn_cast(init)) { @@ -832,7 +832,7 @@ } return true; } - + if (llvm::ConstantDataSequential *CDS = dyn_cast(Init)) { for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { @@ -861,9 +861,9 @@ Builder.CreateDefaultAlignedStore(Init, Loc, isVolatile); return; } - - if (llvm::ConstantDataSequential *CDS = - dyn_cast(Init)) { + + if (llvm::ConstantDataSequential *CDS = + dyn_cast(Init)) { for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { llvm::Constant *Elt = CDS->getElementAsConstant(i); @@ -919,18 +919,29 @@ EmitAutoVarCleanups(emission); } +/// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time +/// markers. +static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts, + const LangOptions &LangOpts) { + // Asan uses markers for use-after-scope checks. + if (CGOpts.SanitizeAddressUseAfterScope) + return true; + + // Disable lifetime markers in msan builds. + // FIXME: Remove this when msan works with lifetime markers. + if (LangOpts.Sanitize.has(SanitizerKind::Memory)) + return false; + + // For now, only in optimized builds. + return CGOpts.OptimizationLevel != 0; +} + /// Emit a lifetime.begin marker if some criteria are satisfied. /// \return a pointer to the temporary size Value if a marker was emitted, null /// otherwise llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size, llvm::Value *Addr) { - // For now, only in optimized builds. - if (CGM.getCodeGenOpts().OptimizationLevel == 0) - return nullptr; - - // Disable lifetime markers in msan builds. - // FIXME: Remove this when msan works with lifetime markers. - if (getLangOpts().Sanitize.has(SanitizerKind::Memory)) + if (!shouldEmitLifetimeMarkers(CGM.getCodeGenOpts(), getLangOpts())) return nullptr; llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size); Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -559,6 +559,14 @@ } } + AsanUseAfterScope = + Args.hasArg(options::OPT_fsanitize_address_use_after_scope); + if (AsanUseAfterScope && !(AllAddedKinds & Address)) { + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fsanitize-address-use-after-scope" + << "-fsanitize=address"; + } + // Parse -link-cxx-sanitizer flag. LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); @@ -655,6 +663,9 @@ CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); + if (AsanUseAfterScope) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-use-after-scope")); + // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as // https://code.google.com/p/address-sanitizer/issues/detail?id=373 Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -490,7 +490,7 @@ Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); - Opts.DebugExplicitImport = Triple.isPS4CPU(); + Opts.DebugExplicitImport = Triple.isPS4CPU(); for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); @@ -706,6 +706,8 @@ Args.hasArg(OPT_fsanitize_memory_use_after_dtor); Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso); Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats); + Opts.SanitizeAddressUseAfterScope = + Args.hasArg(OPT_fsanitize_address_use_after_scope); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); Index: test/CodeGen/lifetime-asan.c =================================================================== --- /dev/null +++ test/CodeGen/lifetime-asan.c @@ -0,0 +1,21 @@ +// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefix=O0 +// RUN: %clang -S -emit-llvm -o - -O0 \ +// RUN: -fsanitize=address -fsanitize-address-use-after-scope %s | \ +// RUN: FileCheck %s -check-prefix=ASAN + +extern int bar(char *A, int n); + +// O0-NOT: @llvm.lifetime.start +int foo(int n) { + if (n) { + // ASAN: @llvm.lifetime.start(i64 10, i8* {{.*}}) + char A[10]; + return bar(A, 1); + // ASAN: @llvm.lifetime.end(i64 10, i8* {{.*}}) + } else { + // ASAN: @llvm.lifetime.start(i64 20, i8* {{.*}}) + char A[20]; + return bar(A, 2); + // ASAN: @llvm.lifetime.end(i64 20, i8* {{.*}}) + } +} Index: test/Driver/fsanitize.c =================================================================== --- test/Driver/fsanitize.c +++ test/Driver/fsanitize.c @@ -103,6 +103,12 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,kernel-address -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANKA // CHECK-SANE-SANKA: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=kernel-address' +// RUN: %clang -target x86_64-linux-gnu -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-USE-AFTER-SCOPE +// CHECK-ONLY-USE-AFTER-SCOPE: '-fsanitize-address-use-after-scope' only allowed with '-fsanitize=address' + +// 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 +// CHECK-USE-AFTER-SCOPE: -cc1{{.*}}-fsanitize-address-use-after-scope + // RUN: %clang -target x86_64-linux-gnu -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-TRACK-ORIGINS // CHECK-ONLY-TRACK-ORIGINS: warning: argument unused during compilation: '-fsanitize-memory-track-origins'