]> granicus.if.org Git - llvm/commitdiff
Asan use-after-scope: don't poison allocas if there were untraced lifetime intrinsics...
authorHans Wennborg <hans@hanshq.net>
Tue, 16 Apr 2019 07:54:20 +0000 (07:54 +0000)
committerHans Wennborg <hans@hanshq.net>
Tue, 16 Apr 2019 07:54:20 +0000 (07:54 +0000)
If there are any intrinsics that cannot be traced back to an alloca, we
might have missed the start of a variable's scope, leading to false
error reports if the variable is poisoned at function entry. Instead, if
there are some intrinsics that can't be traced, fail safe and don't
poison the variables in that function.

Differential revision: https://reviews.llvm.org/D60686

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358478 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Instrumentation/AddressSanitizer.cpp
test/Instrumentation/AddressSanitizer/stack-poisoning-and-lifetime.ll

index 4c827aca20ec8f06ba534a96da82a29716b806b9..d73907c5aca98041188f8d0c0db8e98d66753639 100644 (file)
@@ -884,6 +884,7 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
   };
   SmallVector<AllocaPoisonCall, 8> DynamicAllocaPoisonCallVec;
   SmallVector<AllocaPoisonCall, 8> StaticAllocaPoisonCallVec;
+  bool HasUntracedLifetimeIntrinsic = false;
 
   SmallVector<AllocaInst *, 1> DynamicAllocaVec;
   SmallVector<IntrinsicInst *, 1> StackRestoreVec;
@@ -918,6 +919,14 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
 
     initializeCallbacks(*F.getParent());
 
+    if (HasUntracedLifetimeIntrinsic) {
+      // If there are lifetime intrinsics which couldn't be traced back to an
+      // alloca, we may not know exactly when a variable enters scope, and
+      // therefore should "fail safe" by not poisoning them.
+      StaticAllocaPoisonCallVec.clear();
+      DynamicAllocaPoisonCallVec.clear();
+    }
+
     processDynamicAllocas();
     processStaticAllocas();
 
@@ -1040,8 +1049,12 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
     // Find alloca instruction that corresponds to llvm.lifetime argument.
     AllocaInst *AI =
         llvm::findAllocaForValue(II.getArgOperand(1), AllocaForValue);
+    if (!AI) {
+      HasUntracedLifetimeIntrinsic = true;
+      return;
+    }
     // We're interested only in allocas we can handle.
-    if (!AI || !ASan.isInterestingAlloca(*AI))
+    if (!ASan.isInterestingAlloca(*AI))
       return;
     bool DoPoison = (ID == Intrinsic::lifetime_end);
     AllocaPoisonCall APC = {&II, AI, SizeValue, DoPoison};
index 56a63110a84cbef3b536cdc81ac0ee3e1f5bf0b3..5523da63d373b93ba15b37da2994ff3e995acf15 100644 (file)
@@ -209,6 +209,42 @@ entry:
   ; CHECK: ret void
 }
 
+declare void @foo(i32*)
+define void @PR41481(i1 %b) sanitize_address {
+; CHECK-LABEL: @PR41481
+entry:
+  %p1 = alloca i32
+  %p2 = alloca i32
+  %q1 = bitcast i32* %p1 to i8*
+  %q2 = bitcast i32* %p2 to i8*
+  br label %bb1
+
+  ; Since we cannot account for all lifetime intrinsics in this function, we
+  ; might have missed a lifetime.start one and therefore shouldn't poison the
+  ; allocas at function entry.
+  ; ENTRY: store i64 -935356719533264399
+  ; ENTRY-UAS: store i64 -935356719533264399
+
+bb1:
+  %p = select i1 %b, i32* %p1, i32* %p2
+  %q = select i1 %b, i8*  %q1, i8*  %q2
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %q)
+  call void @foo(i32* %p)
+  br i1 %b, label %bb2, label %bb3
+
+bb2:
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* %q1)
+  br label %end
+
+bb3:
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* %q2)
+  br label %end
+
+end:
+  ret void
+}
+
+
 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)