forked from OSchip/llvm-project
[asan] Added -fsanitize-address-use-after-scope flag
Summary: Also emit lifetime markers for -fsanitize-address-use-after-scope. Asan uses life-time markers for use-after-scope check. PR27453 Reviewers: kcc, eugenis, aizatsky Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D20759 llvm-svn: 271451
This commit is contained in:
parent
f818b86348
commit
9d4eb6f389
|
@ -642,6 +642,9 @@ def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dt
|
|||
def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Level of field padding for AddressSanitizer">;
|
||||
def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable use-after-scope detection in AddressSanitizer">;
|
||||
def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>,
|
||||
Flags<[CoreOption]>;
|
||||
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
|
||||
|
|
|
@ -34,6 +34,7 @@ class SanitizerArgs {
|
|||
bool CfiCrossDso = false;
|
||||
int AsanFieldPadding = 0;
|
||||
bool AsanSharedRuntime = false;
|
||||
bool AsanUseAfterScope = false;
|
||||
bool LinkCXXRuntimes = false;
|
||||
bool NeedPIE = false;
|
||||
bool Stats = false;
|
||||
|
|
|
@ -125,6 +125,8 @@ CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
|
|||
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
|
||||
|
|
|
@ -184,7 +184,7 @@ static void addInstructionCombiningPass(const PassManagerBuilder &Builder,
|
|||
}
|
||||
|
||||
static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
|
||||
legacy::PassManagerBase &PM) {
|
||||
legacy::PassManagerBase &PM) {
|
||||
PM.add(createBoundsCheckingPass());
|
||||
}
|
||||
|
||||
|
@ -210,14 +210,17 @@ static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
|
|||
static_cast<const PassManagerBuilderWrapper&>(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));
|
||||
}
|
||||
|
|
|
@ -679,10 +679,10 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
|
|||
EmitStoreThroughLValue(RValue::get(value), lvalue, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (const CXXDefaultInitExpr *DIE = dyn_cast<CXXDefaultInitExpr>(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<ExprWithCleanups>(init)) {
|
||||
|
@ -832,7 +832,7 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (llvm::ConstantDataSequential *CDS =
|
||||
dyn_cast<llvm::ConstantDataSequential>(Init)) {
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
|
||||
|
@ -861,9 +861,9 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
|
|||
Builder.CreateDefaultAlignedStore(Init, Loc, isVolatile);
|
||||
return;
|
||||
}
|
||||
|
||||
if (llvm::ConstantDataSequential *CDS =
|
||||
dyn_cast<llvm::ConstantDataSequential>(Init)) {
|
||||
|
||||
if (llvm::ConstantDataSequential *CDS =
|
||||
dyn_cast<llvm::ConstantDataSequential>(Init)) {
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
|
||||
llvm::Constant *Elt = CDS->getElementAsConstant(i);
|
||||
|
||||
|
@ -919,18 +919,29 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
|
|||
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);
|
||||
|
|
|
@ -559,6 +559,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
|||
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
|
||||
|
|
|
@ -490,7 +490,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
|||
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('='));
|
||||
|
@ -707,6 +707,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
|||
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);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefix=CHECK-O0
|
||||
// RUN: %clang -S -emit-llvm -o - -O0 \
|
||||
// RUN: -fsanitize=address -fsanitize-address-use-after-scope %s | \
|
||||
// RUN: FileCheck %s -check-prefix=CHECK-ASAN-USE-AFTER-SCOPE
|
||||
|
||||
extern int bar(char *A, int n);
|
||||
|
||||
// CHECK-O0-NOT: @llvm.lifetime.start
|
||||
int foo(int n) {
|
||||
if (n) {
|
||||
// CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start(i64 10, i8* {{.*}})
|
||||
char A[10];
|
||||
return bar(A, 1);
|
||||
// CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end(i64 10, i8* {{.*}})
|
||||
} else {
|
||||
// CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start(i64 20, i8* {{.*}})
|
||||
char A[20];
|
||||
return bar(A, 2);
|
||||
// CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end(i64 20, i8* {{.*}})
|
||||
}
|
||||
}
|
|
@ -103,6 +103,15 @@
|
|||
// 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=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-NO-USE-AFTER-SCOPE
|
||||
// CHECK-ASAN-NO-USE-AFTER-SCOPE-NOT: -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'
|
||||
|
||||
|
|
Loading…
Reference in New Issue