[llvm] r176247 - [msan] Implement sanitize_memory attribute.

Evgeniy Stepanov eugeni.stepanov at gmail.com
Thu Feb 28 03:25:14 PST 2013


Author: eugenis
Date: Thu Feb 28 05:25:14 2013
New Revision: 176247

URL: http://llvm.org/viewvc/llvm-project?rev=176247&view=rev
Log:
[msan] Implement sanitize_memory attribute.

Shadow checks are disabled and memory loads always produce fully initialized
values in functions that don't have a sanitize_memory attribute. Value and
argument shadow is propagated as usual.

This change also updates blacklist behaviour to match the above.

Modified:
    llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp
    llvm/trunk/test/Instrumentation/MemorySanitizer/msan_basic.ll

Modified: llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp?rev=176247&r1=176246&r2=176247&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp Thu Feb 28 05:25:14 2013
@@ -418,6 +418,7 @@ struct MemorySanitizerVisitor : public I
   SmallVector<PHINode *, 16> ShadowPHINodes, OriginPHINodes;
   ValueMap<Value*, Value*> ShadowMap, OriginMap;
   bool InsertChecks;
+  bool LoadShadow;
   OwningPtr<VarArgHelper> VAHelper;
 
   struct ShadowOriginAndInsertPoint {
@@ -432,11 +433,15 @@ struct MemorySanitizerVisitor : public I
   SmallVector<Instruction*, 16> StoreList;
 
   MemorySanitizerVisitor(Function &F, MemorySanitizer &MS)
-    : F(F), MS(MS), VAHelper(CreateVarArgHelper(F, MS, *this)) {
-    InsertChecks = !MS.BL->isIn(F);
+      : F(F), MS(MS), VAHelper(CreateVarArgHelper(F, MS, *this)) {
+    LoadShadow = InsertChecks =
+        !MS.BL->isIn(F) &&
+        F.getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+                                       Attribute::SanitizeMemory);
+
     DEBUG(if (!InsertChecks)
-            dbgs() << "MemorySanitizer is not inserting checks into '"
-                   << F.getName() << "'\n");
+          dbgs() << "MemorySanitizer is not inserting checks into '"
+                 << F.getName() << "'\n");
   }
 
   void materializeStores() {
@@ -831,15 +836,25 @@ struct MemorySanitizerVisitor : public I
     IRBuilder<> IRB(&I);
     Type *ShadowTy = getShadowTy(&I);
     Value *Addr = I.getPointerOperand();
-    Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
-    setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, I.getAlignment(), "_msld"));
+    if (LoadShadow) {
+      Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
+      setShadow(&I,
+                IRB.CreateAlignedLoad(ShadowPtr, I.getAlignment(), "_msld"));
+    } else {
+      setShadow(&I, getCleanShadow(&I));
+    }
 
     if (ClCheckAccessAddress)
       insertCheck(I.getPointerOperand(), &I);
 
     if (MS.TrackOrigins) {
-      unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
-      setOrigin(&I, IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB), Alignment));
+      if (LoadShadow) {
+        unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
+        setOrigin(&I,
+                  IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB), Alignment));
+      } else {
+        setOrigin(&I, getCleanOrigin());
+      }
     }
   }
 
@@ -1405,16 +1420,25 @@ struct MemorySanitizerVisitor : public I
     Value *Addr = I.getArgOperand(0);
 
     Type *ShadowTy = getShadowTy(&I);
-    Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
-    // We don't know the pointer alignment (could be unaligned SSE load!).
-    // Have to assume to worst case.
-    setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, 1, "_msld"));
+    if (LoadShadow) {
+      Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
+      // We don't know the pointer alignment (could be unaligned SSE load!).
+      // Have to assume to worst case.
+      setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, 1, "_msld"));
+    } else {
+      setShadow(&I, getCleanShadow(&I));
+    }
+
 
     if (ClCheckAccessAddress)
       insertCheck(Addr, &I);
 
-    if (MS.TrackOrigins)
-      setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB)));
+    if (MS.TrackOrigins) {
+      if (LoadShadow)
+        setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB)));
+      else
+        setOrigin(&I, getCleanOrigin());
+    }
     return true;
   }
 

Modified: llvm/trunk/test/Instrumentation/MemorySanitizer/msan_basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/MemorySanitizer/msan_basic.ll?rev=176247&r1=176246&r2=176247&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/MemorySanitizer/msan_basic.ll (original)
+++ llvm/trunk/test/Instrumentation/MemorySanitizer/msan_basic.ll Thu Feb 28 05:25:14 2013
@@ -11,7 +11,7 @@ target datalayout = "e-p:64:64:64-i1:8:8
 
 ; Check instrumentation of stores
 
-define void @Store(i32* nocapture %p, i32 %x) nounwind uwtable {
+define void @Store(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
 entry:
   store i32 %x, i32* %p, align 4
   ret void
@@ -39,7 +39,7 @@ entry:
 ; Shadow store has the same alignment as the original store; origin store
 ; does not specify explicit alignment.
 
-define void @AlignedStore(i32* nocapture %p, i32 %x) nounwind uwtable {
+define void @AlignedStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
 entry:
   store i32 %x, i32* %p, align 32
   ret void
@@ -64,7 +64,7 @@ entry:
 
 
 ; load followed by cmp: check that we load the shadow and call __msan_warning.
-define void @LoadAndCmp(i32* nocapture %a) nounwind uwtable {
+define void @LoadAndCmp(i32* nocapture %a) nounwind uwtable sanitize_memory {
 entry:
   %0 = load i32* %a, align 4
   %tobool = icmp eq i32 %0, 0
@@ -89,7 +89,7 @@ declare void @foo(...)
 ; CHECK: ret void
 
 ; Check that we store the shadow for the retval.
-define i32 @ReturnInt() nounwind uwtable readnone {
+define i32 @ReturnInt() nounwind uwtable readnone sanitize_memory {
 entry:
   ret i32 123
 }
@@ -99,7 +99,7 @@ entry:
 ; CHECK: ret i32
 
 ; Check that we get the shadow for the retval.
-define void @CopyRetVal(i32* nocapture %a) nounwind uwtable {
+define void @CopyRetVal(i32* nocapture %a) nounwind uwtable sanitize_memory {
 entry:
   %call = tail call i32 @ReturnInt() nounwind
   store i32 %call, i32* %a, align 4
@@ -114,7 +114,7 @@ entry:
 
 
 ; Check that we generate PHIs for shadow.
-define void @FuncWithPhi(i32* nocapture %a, i32* %b, i32* nocapture %c) nounwind uwtable {
+define void @FuncWithPhi(i32* nocapture %a, i32* %b, i32* nocapture %c) nounwind uwtable sanitize_memory {
 entry:
   %tobool = icmp eq i32* %b, null
   br i1 %tobool, label %if.else, label %if.then
@@ -141,7 +141,7 @@ entry:
 ; CHECK: ret void
 
 ; Compute shadow for "x << 10"
-define void @ShlConst(i32* nocapture %x) nounwind uwtable {
+define void @ShlConst(i32* nocapture %x) nounwind uwtable sanitize_memory {
 entry:
   %0 = load i32* %x, align 4
   %1 = shl i32 %0, 10
@@ -159,7 +159,7 @@ entry:
 ; CHECK: ret void
 
 ; Compute shadow for "10 << x": it should have 'sext i1'.
-define void @ShlNonConst(i32* nocapture %x) nounwind uwtable {
+define void @ShlNonConst(i32* nocapture %x) nounwind uwtable sanitize_memory {
 entry:
   %0 = load i32* %x, align 4
   %1 = shl i32 10, %0
@@ -176,7 +176,7 @@ entry:
 ; CHECK: ret void
 
 ; SExt
-define void @SExt(i32* nocapture %a, i16* nocapture %b) nounwind uwtable {
+define void @SExt(i32* nocapture %a, i16* nocapture %b) nounwind uwtable sanitize_memory {
 entry:
   %0 = load i16* %b, align 2
   %1 = sext i16 %0 to i32
@@ -195,7 +195,7 @@ entry:
 
 
 ; memset
-define void @MemSet(i8* nocapture %x) nounwind uwtable {
+define void @MemSet(i8* nocapture %x) nounwind uwtable sanitize_memory {
 entry:
   call void @llvm.memset.p0i8.i64(i8* %x, i8 42, i64 10, i32 1, i1 false)
   ret void
@@ -209,7 +209,7 @@ declare void @llvm.memset.p0i8.i64(i8* n
 
 
 ; memcpy
-define void @MemCpy(i8* nocapture %x, i8* nocapture %y) nounwind uwtable {
+define void @MemCpy(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory {
 entry:
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false)
   ret void
@@ -223,7 +223,7 @@ declare void @llvm.memcpy.p0i8.p0i8.i64(
 
 
 ; memmove is lowered to a call
-define void @MemMove(i8* nocapture %x, i8* nocapture %y) nounwind uwtable {
+define void @MemMove(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory {
 entry:
   call void @llvm.memmove.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false)
   ret void
@@ -238,7 +238,7 @@ declare void @llvm.memmove.p0i8.p0i8.i64
 
 ; Check that we propagate shadow for "select"
 
-define i32 @Select(i32 %a, i32 %b, i32 %c) nounwind uwtable readnone {
+define i32 @Select(i32 %a, i32 %b, i32 %c) nounwind uwtable readnone sanitize_memory {
 entry:
   %tobool = icmp ne i32 %c, 0
   %cond = select i1 %tobool, i32 %a, i32 %b
@@ -255,7 +255,7 @@ entry:
 ; Select condition is flattened to i1, which is then used to select one of the
 ; argument origins.
 
-define <8 x i16> @SelectVector(<8 x i16> %a, <8 x i16> %b, <8 x i1> %c) nounwind uwtable readnone {
+define <8 x i16> @SelectVector(<8 x i16> %a, <8 x i16> %b, <8 x i1> %c) nounwind uwtable readnone sanitize_memory {
 entry:
   %cond = select <8 x i1> %c, <8 x i16> %a, <8 x i16> %b
   ret <8 x i16> %cond
@@ -268,7 +268,7 @@ entry:
 ; CHECK-ORIGINS: ret <8 x i16>
 
 
-define i8* @IntToPtr(i64 %x) nounwind uwtable readnone {
+define i8* @IntToPtr(i64 %x) nounwind uwtable readnone sanitize_memory {
 entry:
   %0 = inttoptr i64 %x to i8*
   ret i8* %0
@@ -281,7 +281,7 @@ entry:
 ; CHECK: ret i8
 
 
-define i8* @IntToPtr_ZExt(i16 %x) nounwind uwtable readnone {
+define i8* @IntToPtr_ZExt(i16 %x) nounwind uwtable readnone sanitize_memory {
 entry:
   %0 = inttoptr i16 %x to i8*
   ret i8* %0
@@ -296,7 +296,7 @@ entry:
 ; Check that we insert exactly one check on udiv
 ; (2nd arg shadow is checked, 1st arg shadow is propagated)
 
-define i32 @Div(i32 %a, i32 %b) nounwind uwtable readnone {
+define i32 @Div(i32 %a, i32 %b) nounwind uwtable readnone sanitize_memory {
 entry:
   %div = udiv i32 %a, %b
   ret i32 %div
@@ -313,7 +313,7 @@ entry:
 
 ; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
 
-define zeroext i1 @ICmpSLT(i32 %x) nounwind uwtable readnone {
+define zeroext i1 @ICmpSLT(i32 %x) nounwind uwtable readnone sanitize_memory {
   %1 = icmp slt i32 %x, 0
   ret i1 %1
 }
@@ -325,7 +325,7 @@ define zeroext i1 @ICmpSLT(i32 %x) nounw
 ; CHECK-NOT: call void @__msan_warning
 ; CHECK: ret i1
 
-define zeroext i1 @ICmpSGE(i32 %x) nounwind uwtable readnone {
+define zeroext i1 @ICmpSGE(i32 %x) nounwind uwtable readnone sanitize_memory {
   %1 = icmp sge i32 %x, 0
   ret i1 %1
 }
@@ -337,7 +337,7 @@ define zeroext i1 @ICmpSGE(i32 %x) nounw
 ; CHECK-NOT: call void @__msan_warning
 ; CHECK: ret i1
 
-define zeroext i1 @ICmpSGT(i32 %x) nounwind uwtable readnone {
+define zeroext i1 @ICmpSGT(i32 %x) nounwind uwtable readnone sanitize_memory {
   %1 = icmp sgt i32 0, %x
   ret i1 %1
 }
@@ -349,7 +349,7 @@ define zeroext i1 @ICmpSGT(i32 %x) nounw
 ; CHECK-NOT: call void @__msan_warning
 ; CHECK: ret i1
 
-define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone {
+define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone sanitize_memory {
   %1 = icmp sle i32 0, %x
   ret i1 %1
 }
@@ -365,7 +365,7 @@ define zeroext i1 @ICmpSLE(i32 %x) nounw
 ; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
 ; of the vector arguments.
 
-define <2 x i1> @ICmpSLT_vector(<2 x i32*> %x) nounwind uwtable readnone {
+define <2 x i1> @ICmpSLT_vector(<2 x i32*> %x) nounwind uwtable readnone sanitize_memory {
   %1 = icmp slt <2 x i32*> %x, zeroinitializer
   ret <2 x i1> %1
 }
@@ -381,7 +381,7 @@ define <2 x i1> @ICmpSLT_vector(<2 x i32
 ; Check that we propagate shadow for unsigned relational comparisons with
 ; constants
 
-define zeroext i1 @ICmpUGTConst(i32 %x) nounwind uwtable readnone {
+define zeroext i1 @ICmpUGTConst(i32 %x) nounwind uwtable readnone sanitize_memory {
 entry:
   %cmp = icmp ugt i32 %x, 7
   ret i1 %cmp
@@ -400,7 +400,7 @@ entry:
 ; Check that loads of shadow have the same aligment as the original loads.
 ; Check that loads of origin have the aligment of max(4, original alignment).
 
-define i32 @ShadowLoadAlignmentLarge() nounwind uwtable {
+define i32 @ShadowLoadAlignmentLarge() nounwind uwtable sanitize_memory {
   %y = alloca i32, align 64
   %1 = load volatile i32* %y, align 64
   ret i32 %1
@@ -411,7 +411,7 @@ define i32 @ShadowLoadAlignmentLarge() n
 ; CHECK: load volatile i32* {{.*}} align 64
 ; CHECK: ret i32
 
-define i32 @ShadowLoadAlignmentSmall() nounwind uwtable {
+define i32 @ShadowLoadAlignmentSmall() nounwind uwtable sanitize_memory {
   %y = alloca i32, align 2
   %1 = load volatile i32* %y, align 2
   ret i32 %1
@@ -433,7 +433,7 @@ define i32 @ShadowLoadAlignmentSmall() n
 ; Check that the same bit manipulation is applied to the shadow values.
 ; Check that there is a zero test of the shadow of %idx argument, where present.
 
-define i32 @ExtractElement(<4 x i32> %vec, i32 %idx) {
+define i32 @ExtractElement(<4 x i32> %vec, i32 %idx) sanitize_memory {
   %x = extractelement <4 x i32> %vec, i32 %idx
   ret i32 %x
 }
@@ -444,7 +444,7 @@ define i32 @ExtractElement(<4 x i32> %ve
 ; CHECK: extractelement
 ; CHECK: ret i32
 
-define <4 x i32> @InsertElement(<4 x i32> %vec, i32 %idx, i32 %x) {
+define <4 x i32> @InsertElement(<4 x i32> %vec, i32 %idx, i32 %x) sanitize_memory {
   %vec1 = insertelement <4 x i32> %vec, i32 %x, i32 %idx
   ret <4 x i32> %vec1
 }
@@ -455,7 +455,7 @@ define <4 x i32> @InsertElement(<4 x i32
 ; CHECK: insertelement
 ; CHECK: ret <4 x i32>
 
-define <4 x i32> @ShuffleVector(<4 x i32> %vec, <4 x i32> %vec1) {
+define <4 x i32> @ShuffleVector(<4 x i32> %vec, <4 x i32> %vec1) sanitize_memory {
   %vec2 = shufflevector <4 x i32> %vec, <4 x i32> %vec1,
                         <4 x i32> <i32 0, i32 4, i32 1, i32 5>
   ret <4 x i32> %vec2
@@ -469,7 +469,7 @@ define <4 x i32> @ShuffleVector(<4 x i32
 
 
 ; Test bswap intrinsic instrumentation
-define i32 @BSwap(i32 %x) nounwind uwtable readnone {
+define i32 @BSwap(i32 %x) nounwind uwtable readnone sanitize_memory {
   %y = tail call i32 @llvm.bswap.i32(i32 %x)
   ret i32 %y
 }
@@ -487,7 +487,7 @@ declare i32 @llvm.bswap.i32(i32) nounwin
 
 ; Store intrinsic.
 
-define void @StoreIntrinsic(i8* %p, <4 x float> %x) nounwind uwtable {
+define void @StoreIntrinsic(i8* %p, <4 x float> %x) nounwind uwtable sanitize_memory {
   call void @llvm.x86.sse.storeu.ps(i8* %p, <4 x float> %x)
   ret void
 }
@@ -504,7 +504,7 @@ declare void @llvm.x86.sse.storeu.ps(i8*
 
 ; Load intrinsic.
 
-define <16 x i8> @LoadIntrinsic(i8* %p) nounwind uwtable {
+define <16 x i8> @LoadIntrinsic(i8* %p) nounwind uwtable sanitize_memory {
   %call = call <16 x i8> @llvm.x86.sse3.ldu.dq(i8* %p)
   ret <16 x i8> %call
 }
@@ -530,7 +530,7 @@ declare <16 x i8> @llvm.x86.sse3.ldu.dq(
 ; Check that shadow is OR'ed, and origin is Select'ed
 ; And no shadow checks!
 
-define <8 x i16> @Paddsw128(<8 x i16> %a, <8 x i16> %b) nounwind uwtable {
+define <8 x i16> @Paddsw128(<8 x i16> %a, <8 x i16> %b) nounwind uwtable sanitize_memory {
   %call = call <8 x i16> @llvm.x86.sse2.padds.w(<8 x i16> %a, <8 x i16> %b)
   ret <8 x i16> %call
 }
@@ -559,7 +559,7 @@ declare <8 x i16> @llvm.x86.sse2.padds.w
 ; Test handling of vectors of pointers.
 ; Check that shadow of such vector is a vector of integers.
 
-define <8 x i8*> @VectorOfPointers(<8 x i8*>* %p) nounwind uwtable {
+define <8 x i8*> @VectorOfPointers(<8 x i8*>* %p) nounwind uwtable sanitize_memory {
   %x = load <8 x i8*>* %p
   ret <8 x i8*> %x
 }
@@ -574,7 +574,7 @@ define <8 x i8*> @VectorOfPointers(<8 x
 
 declare void @llvm.va_copy(i8*, i8*) nounwind
 
-define void @VACopy(i8* %p1, i8* %p2) nounwind uwtable {
+define void @VACopy(i8* %p1, i8* %p2) nounwind uwtable sanitize_memory {
   call void @llvm.va_copy(i8* %p1, i8* %p2) nounwind
   ret void
 }
@@ -587,7 +587,7 @@ define void @VACopy(i8* %p1, i8* %p2) no
 ; Test handling of volatile stores.
 ; Check that MemorySanitizer does not add a check of the value being stored.
 
-define void @VolatileStore(i32* nocapture %p, i32 %x) nounwind uwtable {
+define void @VolatileStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
 entry:
   store volatile i32 %x, i32* %p, align 4
   ret void
@@ -596,3 +596,30 @@ entry:
 ; CHECK: @VolatileStore
 ; CHECK-NOT: @__msan_warning
 ; CHECK: ret void
+
+
+; Test that checks are omitted but shadow propagation is kept if
+; sanitize_memory attribute is missing.
+
+define i32 @NoSanitizeMemory(i32 %x) uwtable {
+entry:
+  %tobool = icmp eq i32 %x, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @bar()
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.then
+  ret i32 %x
+}
+
+declare void @bar()
+
+; CHECK: @NoSanitizeMemory
+; CHECK-NOT: @__msan_warning
+; CHECK: load i32* {{.*}} @__msan_param_tls
+; CHECK-NOT: @__msan_warning
+; CHECK: store {{.*}} @__msan_retval_tls
+; CHECK-NOT: @__msan_warning
+; CHECK: ret i32





More information about the llvm-commits mailing list