From e3a032a7408ccff451cb5c081511797e05dca162 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Jul 2016 22:04:38 +0000 Subject: [PATCH] Unpoison stack before resume instruction Summary: Clang inserts cleanup code before resume similar way as before return instruction. This makes asan poison local variables causing false use-after-scope reports. __asan_handle_no_return does not help here as it was executed before llvm.lifetime.end inserted into resume block. To avoid false report we need to unpoison stack for resume same way as for return. PR27453 Reviewers: kcc, eugenis Differential Revision: https://reviews.llvm.org/D22661 llvm-svn: 276480 --- .../Instrumentation/AddressSanitizer.cpp | 6 ++ .../AddressSanitizer/lifetime-throw.ll | 106 +++++++++++++++++++++ .../Instrumentation/AddressSanitizer/lifetime.ll | 2 +- 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Instrumentation/AddressSanitizer/lifetime-throw.ll diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 27b68b0..0dbd5c0 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -676,6 +676,12 @@ struct FunctionStackPoisoner : public InstVisitor { /// \brief Collect all Ret instructions. void visitReturnInst(ReturnInst &RI) { RetVec.push_back(&RI); } + /// \brief Collect all Resume instructions. + void visitResumeInst(ResumeInst &RI) { RetVec.push_back(&RI); } + + /// \brief Collect all CatchReturnInst instructions. + void visitCleanupReturnInst(CleanupReturnInst &CRI) { RetVec.push_back(&CRI); } + void unpoisonDynamicAllocasBeforeInst(Instruction *InstBefore, Value *SavedStack) { IRBuilder<> IRB(InstBefore); diff --git a/llvm/test/Instrumentation/AddressSanitizer/lifetime-throw.ll b/llvm/test/Instrumentation/AddressSanitizer/lifetime-throw.ll new file mode 100644 index 0000000..6a4ec44 --- /dev/null +++ b/llvm/test/Instrumentation/AddressSanitizer/lifetime-throw.ll @@ -0,0 +1,106 @@ +; Test handling of llvm.lifetime intrinsics with C++ exceptions. +; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.ABC = type { i32 } + +$_ZN3ABCD2Ev = comdat any +$_ZTS3ABC = comdat any +$_ZTI3ABC = comdat any + +@_ZTVN10__cxxabiv117__class_type_infoE = external global i8* +@_ZTS3ABC = linkonce_odr constant [5 x i8] c"3ABC\00", comdat +@_ZTI3ABC = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @_ZTS3ABC, i32 0, i32 0) }, comdat + +define void @Throw() sanitize_address personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: define void @Throw() +entry: + %x = alloca %struct.ABC, align 4 + %0 = bitcast %struct.ABC* %x to i8* + call void @llvm.lifetime.start(i64 4, i8* %0) + ; CHECK: call void @__asan_unpoison_stack_memory + ; CHECK-NEXT: @llvm.lifetime.start + + %exception = call i8* @__cxa_allocate_exception(i64 4) + invoke void @__cxa_throw(i8* %exception, i8* bitcast ({ i8*, i8* }* @_ZTI3ABC to i8*), i8* bitcast (void (%struct.ABC*)* @_ZN3ABCD2Ev to i8*)) noreturn + to label %unreachable unwind label %lpad + ; CHECK: call void @__asan_handle_no_return + ; CHECK-NEXT: @__cxa_throw + +lpad: + %1 = landingpad { i8*, i32 } + cleanup + call void @_ZN3ABCD2Ev(%struct.ABC* nonnull %x) + call void @llvm.lifetime.end(i64 4, i8* %0) + ; CHECK: call void @__asan_poison_stack_memory + ; CHECK-NEXT: @llvm.lifetime.end + + resume { i8*, i32 } %1 + ; CHECK: call void @__asan_unpoison_stack_memory + ; CHECK-NEXT: resume + +unreachable: + unreachable +} + +%rtti.TypeDescriptor9 = type { i8**, i8*, [10 x i8] } +%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } +%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } +%eh.ThrowInfo = type { i32, i32, i32, i32 } + +$"\01??1ABC@@QEAA@XZ" = comdat any +$"\01??_R0?AUABC@@@8" = comdat any +$"_CT??_R0?AUABC@@@84" = comdat any +$"_CTA1?AUABC@@" = comdat any +$"_TI1?AUABC@@" = comdat any + +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0?AUABC@@@8" = linkonce_odr global %rtti.TypeDescriptor9 { i8** @"\01??_7type_info@@6B@", i8* null, [10 x i8] c".?AUABC@@\00" }, comdat +@__ImageBase = external constant i8 +@"_CT??_R0?AUABC@@@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor9* @"\01??_R0?AUABC@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat +@"_CTA1?AUABC@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0?AUABC@@@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat +@"_TI1?AUABC@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (void (%struct.ABC*)* @"\01??1ABC@@QEAA@XZ" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @"_CTA1?AUABC@@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat + +define void @ThrowWin() sanitize_address personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: define void @ThrowWin() +entry: + %x = alloca %struct.ABC, align 4 + %tmp = alloca %struct.ABC, align 4 + %0 = bitcast %struct.ABC* %x to i8* + call void @llvm.lifetime.start(i64 4, i8* %0) + ; CHECK: call void @__asan_unpoison_stack_memory + ; CHECK-NEXT: @llvm.lifetime.start + + %1 = bitcast %struct.ABC* %tmp to i8* + invoke void @_CxxThrowException(i8* %1, %eh.ThrowInfo* nonnull @"_TI1?AUABC@@") noreturn + to label %unreachable unwind label %ehcleanup + ; CHECK: call void @__asan_handle_no_return + ; CHECK-NEXT: @_CxxThrowException + +ehcleanup: + %2 = cleanuppad within none [] + call void @"\01??1ABC@@QEAA@XZ"(%struct.ABC* nonnull %x) [ "funclet"(token %2) ] + call void @llvm.lifetime.end(i64 4, i8* %0) + ; CHECK: call void @__asan_poison_stack_memory + ; CHECK-NEXT: @llvm.lifetime.end + + cleanupret from %2 unwind to caller + ; CHECK: call void @__asan_unpoison_stack_memory + ; CHECK-NEXT: cleanupret + +unreachable: + unreachable +} + + +declare i32 @__gxx_personality_v0(...) +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) +declare void @__cxa_throw(i8*, i8*, i8*) local_unnamed_addr +declare i8* @__cxa_allocate_exception(i64) local_unnamed_addr +declare void @_ZN3ABCD2Ev(%struct.ABC* %this) unnamed_addr +declare void @"\01??1ABC@@QEAA@XZ"(%struct.ABC* %this) +declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) +declare i32 @__CxxFrameHandler3(...) diff --git a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll index f8c8d47..dc87d50 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll @@ -1,4 +1,4 @@ -; Test hanlding of llvm.lifetime intrinsics. +; Test handling of llvm.lifetime intrinsics. ; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -S | FileCheck %s ; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -asan-instrument-allocas=0 -S | FileCheck %s --check-prefix=CHECK-NO-DYNAMIC -- 2.7.4