diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -1149,11 +1149,11 @@ const DataLayout &DL = F.getParent()->getDataLayout(); const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment); unsigned StoreSize = DL.getTypeStoreSize(Shadow->getType()); - if (Shadow->getType()->isAggregateType()) { + if (Shadow->getType()->isArrayTy()) { paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, OriginAlignment); } else { - Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, @@ -1172,8 +1172,7 @@ IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), Origin}); } else { - Value *Cmp = IRB.CreateICmpNE( - ConvertedShadow, getCleanShadow(ConvertedShadow), "_mscmp"); + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); Instruction *CheckTerm = SplitBlockAndInsertIfThen( Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights); IRBuilder<> IRBNew(CheckTerm); @@ -1224,7 +1223,7 @@ bool AsCall) { IRBuilder<> IRB(OrigIns); LLVM_DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); - Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); LLVM_DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { @@ -1246,8 +1245,7 @@ ? Origin : (Value *)IRB.getInt32(0)}); } else { - Value *Cmp = IRB.CreateICmpNE(ConvertedShadow, - getCleanShadow(ConvertedShadow), "_mscmp"); + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); Instruction *CheckTerm = SplitBlockAndInsertIfThen( Cmp, OrigIns, /* Unreachable */ !MS.Recover, MS.ColdCallWeights); @@ -1391,14 +1389,49 @@ return ty; } - /// Convert a shadow value to it's flattened variant. - Value *convertToShadowTyNoVec(Value *V, IRBuilder<> &IRB) { + /// Extract combined shadow of struct elements as a bool + Value *collapseStructShadow(StructType *Struct, Value *Shadow, + IRBuilder<> &IRB) { + Value *FalseVal = IRB.getIntN(/* width */ 1, /* value */ 0); + Value *Aggregator = FalseVal; + + for (unsigned Idx = 0; Idx < Struct->getNumElements(); Idx++) { + // Combine by ORing together each element's bool shadow + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); + Value *ShadowBool = convertToBool(ShadowInner, IRB); + + if (Aggregator != FalseVal) + Aggregator = IRB.CreateOr(Aggregator, ShadowBool); + else + Aggregator = ShadowBool; + } + + return Aggregator; + } + + /// Convert a shadow value to it's flattened variant. The resulting + /// shadow may not necessarily have the same bit width as the input + /// value, but it will always be comparable to zero. + Value *convertShadowToScalar(Value *V, IRBuilder<> &IRB) { + if (StructType *Struct = dyn_cast(V->getType())) + return collapseStructShadow(Struct, V, IRB); Type *Ty = V->getType(); Type *NoVecTy = getShadowTyNoVec(Ty); if (Ty == NoVecTy) return V; return IRB.CreateBitCast(V, NoVecTy); } + // Convert a scalar value to an i1 by comparing with 0 + Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &name = "") { + Type *VTy = V->getType(); + assert(VTy->isIntegerTy()); + if (VTy->getIntegerBitWidth() == 1) + // Just converting a bool to a bool, so do nothing. + return V; + return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), name); + } + /// Compute the integer shadow offset that corresponds to a given /// application address. /// @@ -1732,8 +1765,10 @@ if (!InsertChecks) return; #ifndef NDEBUG Type *ShadowTy = Shadow->getType(); - assert((isa(ShadowTy) || isa(ShadowTy)) && - "Can only insert checks for integer and vector shadow types"); + assert( + (isa(ShadowTy) || isa(ShadowTy) || + isa(ShadowTy)) && + "Can only insert checks for integer, vector, and struct shadow types"); #endif InstrumentationList.push_back( ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns)); @@ -2088,7 +2123,7 @@ Constant *ConstOrigin = dyn_cast(OpOrigin); // No point in adding something that might result in 0 origin value. if (!ConstOrigin || !ConstOrigin->isNullValue()) { - Value *FlatShadow = MSV->convertToShadowTyNoVec(OpShadow, IRB); + Value *FlatShadow = MSV->convertShadowToScalar(OpShadow, IRB); Value *Cond = IRB.CreateICmpNE(FlatShadow, MSV->getCleanShadow(FlatShadow)); Origin = IRB.CreateSelect(Cond, OpOrigin, Origin); diff --git a/llvm/test/Instrumentation/MemorySanitizer/check-struct.ll b/llvm/test/Instrumentation/MemorySanitizer/check-struct.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/MemorySanitizer/check-struct.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=1 -S -passes='module(msan-module),function(msan)' 2>&1 | \ +; RUN: FileCheck -allow-deprecated-dag-overlap -check-prefixes=CHECK,CHECK-ORIGINS %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK-LABEL: @main +define { i32, i8 } @main() sanitize_memory { +; CHECK: [[P:%.*]] = inttoptr i64 0 to { i32, i8 }* + %p = inttoptr i64 0 to { i32, i8 } * +; CHECK: [[O:%.*]] = load { i32, i8 }, { i32, i8 }* [[P]] + %o = load { i32, i8 }, { i32, i8 } *%p +; CHECK: [[FIELD0:%.+]] = extractvalue { i32, i8 } %_msld, 0 +; CHECK: [[F0_POISONED:%.+]] = icmp ne i32 [[FIELD0]] +; CHECK: [[FIELD1:%.+]] = extractvalue { i32, i8 } %_msld, 1 +; CHECK: [[F1_POISONED:%.+]] = icmp ne i8 [[FIELD1]] +; CHECK: [[F1_OR:%.+]] = or i1 [[F0_POISONED]], [[F1_POISONED]] +; CHECK-NOT: icmp ne i1 {{.*}}, false +; CHECK: br i1 [[F1_OR]] +; CHECK: call void @__msan_warning +; CHECK: ret { i32, i8 } [[O]] + ret { i32, i8 } %o +} diff --git a/llvm/test/Instrumentation/MemorySanitizer/msan_x86_bts_asm.ll b/llvm/test/Instrumentation/MemorySanitizer/msan_x86_bts_asm.ll --- a/llvm/test/Instrumentation/MemorySanitizer/msan_x86_bts_asm.ll +++ b/llvm/test/Instrumentation/MemorySanitizer/msan_x86_bts_asm.ll @@ -92,8 +92,7 @@ ; CHECK: [[MSPROP:%.*]] = trunc i8 [[MSLD]] to i1 ; Is the shadow poisoned? -; CHECK: [[MSCMP:%.*]] = icmp ne i1 [[MSPROP]], false -; CHECK: br i1 [[MSCMP]], label %[[IFTRUE:.*]], label {{.*}} +; CHECK: br i1 [[MSPROP]], label %[[IFTRUE:.*]], label {{.*}} ; If yes, raise a warning. ; CHECK: [[IFTRUE]]: