X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTransforms%2FInstrumentation%2FMemorySanitizer.cpp;h=4a7669fe5d055aa02f4a1eae636614a6d3bbe8c7;hp=b08a4773f95fcecaa0da80855094c170beef53a5;hb=e376441786f994d7d3f27817e163d226d31b641e;hpb=7bf5a63e119df4720637ea0f727a95cd8e0d93b6 diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp index b08a4773f95..4a7669fe5d0 100644 --- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -127,6 +127,10 @@ static const uint64_t kOriginOffset64 = 1ULL << 45; static const unsigned kMinOriginAlignment = 4; static const unsigned kShadowTLSAlignment = 8; +// These constants must be kept in sync with the ones in msan.h. +static const unsigned kParamTLSSize = 800; +static const unsigned kRetvalTLSSize = 800; + // Accesses sizes are powers of two: 1, 2, 4, 8. static const size_t kNumberOfAccessSizes = 4; @@ -195,6 +199,13 @@ static cl::opt ClWrapIndirectCallsFast("msan-wrap-indirect-calls-fast", cl::desc("Do not wrap indirect calls with target in the same module"), cl::Hidden, cl::init(true)); +// This is an experiment to enable handling of cases where shadow is a non-zero +// compile-time constant. For some unexplainable reason they were silently +// ignored in the instrumentation. +static cl::opt ClCheckConstantShadow("msan-check-constant-shadow", + cl::desc("Insert checks for constant shadow values"), + cl::Hidden, cl::init(false)); + namespace { /// \brief An instrumentation pass implementing detection of uninitialized @@ -356,7 +367,7 @@ void MemorySanitizer::initializeCallbacks(Module &M) { // Create globals. RetvalTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), 8), false, + M, ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8), false, GlobalVariable::ExternalLinkage, nullptr, "__msan_retval_tls", nullptr, GlobalVariable::InitialExecTLSModel); RetvalOriginTLS = new GlobalVariable( @@ -364,16 +375,16 @@ void MemorySanitizer::initializeCallbacks(Module &M) { "__msan_retval_origin_tls", nullptr, GlobalVariable::InitialExecTLSModel); ParamTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), 1000), false, + M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, GlobalVariable::ExternalLinkage, nullptr, "__msan_param_tls", nullptr, GlobalVariable::InitialExecTLSModel); ParamOriginTLS = new GlobalVariable( - M, ArrayType::get(OriginTy, 1000), false, GlobalVariable::ExternalLinkage, - nullptr, "__msan_param_origin_tls", nullptr, - GlobalVariable::InitialExecTLSModel); + M, ArrayType::get(OriginTy, kParamTLSSize / 4), false, + GlobalVariable::ExternalLinkage, nullptr, "__msan_param_origin_tls", + nullptr, GlobalVariable::InitialExecTLSModel); VAArgTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), 1000), false, + M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, GlobalVariable::ExternalLinkage, nullptr, "__msan_va_arg_tls", nullptr, GlobalVariable::InitialExecTLSModel); VAArgOverflowSizeTLS = new GlobalVariable( @@ -511,7 +522,7 @@ struct MemorySanitizerVisitor : public InstVisitor { // The following flags disable parts of MSan instrumentation based on // blacklist contents and command-line options. bool InsertChecks; - bool LoadShadow; + bool PropagateShadow; bool PoisonStack; bool PoisonUndef; bool CheckReturnValue; @@ -532,7 +543,7 @@ struct MemorySanitizerVisitor : public InstVisitor { bool SanitizeFunction = F.getAttributes().hasAttribute( AttributeSet::FunctionIndex, Attribute::SanitizeMemory); InsertChecks = SanitizeFunction; - LoadShadow = SanitizeFunction; + PropagateShadow = SanitizeFunction; PoisonStack = SanitizeFunction && ClPoisonStack; PoisonUndef = SanitizeFunction && ClPoisonUndef; // FIXME: Consider using SpecialCaseList to specify a list of functions that @@ -559,7 +570,8 @@ struct MemorySanitizerVisitor : public InstVisitor { // TODO(eugenis): handle non-zero constant shadow by inserting an // unconditional check (can not simply fail compilation as this could // be in the dead code). - if (isa(ConvertedShadow)) return; + if (!ClCheckConstantShadow) + if (isa(ConvertedShadow)) return; unsigned TypeSizeInBits = MS.DL->getTypeSizeInBits(ConvertedShadow->getType()); unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); @@ -615,8 +627,9 @@ struct MemorySanitizerVisitor : public InstVisitor { DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); - // See the comment in materializeStores(). - if (isa(ConvertedShadow)) return; + // See the comment in storeOrigin(). + if (!ClCheckConstantShadow) + if (isa(ConvertedShadow)) return; unsigned TypeSizeInBits = MS.DL->getTypeSizeInBits(ConvertedShadow->getType()); unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); @@ -721,8 +734,7 @@ struct MemorySanitizerVisitor : public InstVisitor { size_t NumValues = PN->getNumIncomingValues(); for (size_t v = 0; v < NumValues; v++) { PNS->addIncoming(getShadow(PN, v), PN->getIncomingBlock(v)); - if (PNO) - PNO->addIncoming(getOrigin(PN, v), PN->getIncomingBlock(v)); + if (PNO) PNO->addIncoming(getOrigin(PN, v), PN->getIncomingBlock(v)); } } @@ -764,6 +776,10 @@ struct MemorySanitizerVisitor : public InstVisitor { return VectorType::get(IntegerType::get(*MS.C, EltSize), VT->getNumElements()); } + if (ArrayType *AT = dyn_cast(OrigTy)) { + return ArrayType::get(getShadowTy(AT->getElementType()), + AT->getNumElements()); + } if (StructType *ST = dyn_cast(OrigTy)) { SmallVector Elements; for (unsigned i = 0, n = ST->getNumElements(); i < n; i++) @@ -856,7 +872,7 @@ struct MemorySanitizerVisitor : public InstVisitor { /// \brief Set SV to be the shadow value for V. void setShadow(Value *V, Value *SV) { assert(!ShadowMap.count(V) && "Values may only have one shadow"); - ShadowMap[V] = SV; + ShadowMap[V] = PropagateShadow ? SV : getCleanShadow(V); } /// \brief Set Origin to be the origin value for V. @@ -883,11 +899,18 @@ struct MemorySanitizerVisitor : public InstVisitor { assert(ShadowTy); if (isa(ShadowTy) || isa(ShadowTy)) return Constant::getAllOnesValue(ShadowTy); - StructType *ST = cast(ShadowTy); - SmallVector Vals; - for (unsigned i = 0, n = ST->getNumElements(); i < n; i++) - Vals.push_back(getPoisonedShadow(ST->getElementType(i))); - return ConstantStruct::get(ST, Vals); + if (ArrayType *AT = dyn_cast(ShadowTy)) { + SmallVector Vals(AT->getNumElements(), + getPoisonedShadow(AT->getElementType())); + return ConstantArray::get(AT, Vals); + } + if (StructType *ST = dyn_cast(ShadowTy)) { + SmallVector Vals; + for (unsigned i = 0, n = ST->getNumElements(); i < n; i++) + Vals.push_back(getPoisonedShadow(ST->getElementType(i))); + return ConstantStruct::get(ST, Vals); + } + llvm_unreachable("Unexpected shadow type"); } /// \brief Create a dirty shadow for a given value. @@ -908,6 +931,7 @@ struct MemorySanitizerVisitor : public InstVisitor { /// This function either returns the value set earlier with setShadow, /// or extracts if from ParamTLS (for function arguments). Value *getShadow(Value *V) { + if (!PropagateShadow) return getCleanShadow(V); if (Instruction *I = dyn_cast(V)) { // For instructions the shadow is already stored in the map. Value *Shadow = ShadowMap[V]; @@ -941,6 +965,7 @@ struct MemorySanitizerVisitor : public InstVisitor { ? MS.DL->getTypeAllocSize(FArg.getType()->getPointerElementType()) : MS.DL->getTypeAllocSize(FArg.getType()); if (A == &FArg) { + bool Overflow = ArgOffset + Size > kParamTLSSize; Value *Base = getShadowPtrForArgument(&FArg, EntryIRB, ArgOffset); if (FArg.hasByValAttr()) { // ByVal pointer itself has clean shadow. We copy the actual @@ -951,25 +976,38 @@ struct MemorySanitizerVisitor : public InstVisitor { Type *EltType = A->getType()->getPointerElementType(); ArgAlign = MS.DL->getABITypeAlignment(EltType); } - unsigned CopyAlign = std::min(ArgAlign, kShadowTLSAlignment); - Value *Cpy = EntryIRB.CreateMemCpy( - getShadowPtr(V, EntryIRB.getInt8Ty(), EntryIRB), Base, Size, - CopyAlign); - DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n"); - (void)Cpy; + if (Overflow) { + // ParamTLS overflow. + EntryIRB.CreateMemSet( + getShadowPtr(V, EntryIRB.getInt8Ty(), EntryIRB), + Constant::getNullValue(EntryIRB.getInt8Ty()), Size, ArgAlign); + } else { + unsigned CopyAlign = std::min(ArgAlign, kShadowTLSAlignment); + Value *Cpy = EntryIRB.CreateMemCpy( + getShadowPtr(V, EntryIRB.getInt8Ty(), EntryIRB), Base, Size, + CopyAlign); + DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n"); + (void)Cpy; + } *ShadowPtr = getCleanShadow(V); } else { - *ShadowPtr = EntryIRB.CreateAlignedLoad(Base, kShadowTLSAlignment); + if (Overflow) { + // ParamTLS overflow. + *ShadowPtr = getCleanShadow(V); + } else { + *ShadowPtr = + EntryIRB.CreateAlignedLoad(Base, kShadowTLSAlignment); + } } DEBUG(dbgs() << " ARG: " << FArg << " ==> " << **ShadowPtr << "\n"); - if (MS.TrackOrigins) { + if (MS.TrackOrigins && !Overflow) { Value *OriginPtr = getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset); setOrigin(A, EntryIRB.CreateLoad(OriginPtr)); } } - ArgOffset += DataLayout::RoundUpAlignment(Size, kShadowTLSAlignment); + ArgOffset += RoundUpToAlignment(Size, kShadowTLSAlignment); } assert(*ShadowPtr && "Could not find shadow for an argument"); return *ShadowPtr; @@ -1024,9 +1062,16 @@ struct MemorySanitizerVisitor : public InstVisitor { /// UMR warning in runtime if the value is not fully defined. void insertShadowCheck(Value *Val, Instruction *OrigIns) { assert(Val); - Instruction *Shadow = dyn_cast_or_null(getShadow(Val)); - if (!Shadow) return; - Instruction *Origin = dyn_cast_or_null(getOrigin(Val)); + Value *Shadow, *Origin; + if (ClCheckConstantShadow) { + Shadow = getShadow(Val); + if (!Shadow) return; + Origin = getOrigin(Val); + } else { + Shadow = dyn_cast_or_null(getShadow(Val)); + if (!Shadow) return; + Origin = dyn_cast_or_null(getOrigin(Val)); + } insertShadowCheck(Shadow, Origin, OrigIns); } @@ -1075,7 +1120,7 @@ struct MemorySanitizerVisitor : public InstVisitor { IRBuilder<> IRB(I.getNextNode()); Type *ShadowTy = getShadowTy(&I); Value *Addr = I.getPointerOperand(); - if (LoadShadow) { + if (PropagateShadow) { Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB); setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, I.getAlignment(), "_msld")); @@ -1090,7 +1135,7 @@ struct MemorySanitizerVisitor : public InstVisitor { I.setOrdering(addAcquireOrdering(I.getOrdering())); if (MS.TrackOrigins) { - if (LoadShadow) { + if (PropagateShadow) { unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment()); setOrigin(&I, IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB), Alignment)); @@ -1757,7 +1802,7 @@ struct MemorySanitizerVisitor : public InstVisitor { Value *Addr = I.getArgOperand(0); Type *ShadowTy = getShadowTy(&I); - if (LoadShadow) { + if (PropagateShadow) { Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB); // We don't know the pointer alignment (could be unaligned SSE load!). // Have to assume to worst case. @@ -1770,7 +1815,7 @@ struct MemorySanitizerVisitor : public InstVisitor { insertShadowCheck(Addr, &I); if (MS.TrackOrigins) { - if (LoadShadow) + if (PropagateShadow) setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB))); else setOrigin(&I, getCleanOrigin()); @@ -1859,7 +1904,7 @@ struct MemorySanitizerVisitor : public InstVisitor { Value *Op = I.getArgOperand(0); Type *OpType = Op->getType(); Function *BswapFunc = Intrinsic::getDeclaration( - F.getParent(), Intrinsic::bswap, ArrayRef(&OpType, 1)); + F.getParent(), Intrinsic::bswap, makeArrayRef(&OpType, 1)); setShadow(&I, IRB.CreateCall(BswapFunc, getShadow(Op))); setOrigin(&I, getOrigin(Op)); } @@ -2313,26 +2358,32 @@ struct MemorySanitizerVisitor : public InstVisitor { Value *ArgShadowBase = getShadowPtrForArgument(A, IRB, ArgOffset); DEBUG(dbgs() << " Arg#" << i << ": " << *A << " Shadow: " << *ArgShadow << "\n"); + bool ArgIsInitialized = false; if (CS.paramHasAttr(i + 1, Attribute::ByVal)) { assert(A->getType()->isPointerTy() && "ByVal argument is not a pointer!"); Size = MS.DL->getTypeAllocSize(A->getType()->getPointerElementType()); - unsigned Alignment = CS.getParamAlignment(i + 1); + if (ArgOffset + Size > kParamTLSSize) break; + unsigned ParamAlignment = CS.getParamAlignment(i + 1); + unsigned Alignment = std::min(ParamAlignment, kShadowTLSAlignment); Store = IRB.CreateMemCpy(ArgShadowBase, getShadowPtr(A, Type::getInt8Ty(*MS.C), IRB), Size, Alignment); } else { Size = MS.DL->getTypeAllocSize(A->getType()); + if (ArgOffset + Size > kParamTLSSize) break; Store = IRB.CreateAlignedStore(ArgShadow, ArgShadowBase, kShadowTLSAlignment); + Constant *Cst = dyn_cast(ArgShadow); + if (Cst && Cst->isNullValue()) ArgIsInitialized = true; } - if (MS.TrackOrigins) + if (MS.TrackOrigins && !ArgIsInitialized) IRB.CreateStore(getOrigin(A), getOriginPtrForArgument(A, IRB, ArgOffset)); (void)Store; assert(Size != 0 && Store != nullptr); DEBUG(dbgs() << " Param:" << *Store << "\n"); - ArgOffset += DataLayout::RoundUpAlignment(Size, 8); + ArgOffset += RoundUpToAlignment(Size, 8); } DEBUG(dbgs() << " done with call args\n"); @@ -2394,6 +2445,11 @@ struct MemorySanitizerVisitor : public InstVisitor { void visitPHINode(PHINode &I) { IRBuilder<> IRB(&I); + if (!PropagateShadow) { + setShadow(&I, getCleanShadow(&I)); + return; + } + ShadowPHINodes.push_back(&I); setShadow(&I, IRB.CreatePHI(getShadowTy(&I), I.getNumIncomingValues(), "_msphi_s")); @@ -2608,7 +2664,7 @@ struct VarArgAMD64Helper : public VarArgHelper { Type *RealTy = A->getType()->getPointerElementType(); uint64_t ArgSize = MS.DL->getTypeAllocSize(RealTy); Value *Base = getShadowPtrForVAArgument(RealTy, IRB, OverflowOffset); - OverflowOffset += DataLayout::RoundUpAlignment(ArgSize, 8); + OverflowOffset += RoundUpToAlignment(ArgSize, 8); IRB.CreateMemCpy(Base, MSV.getShadowPtr(A, IRB.getInt8Ty(), IRB), ArgSize, kShadowTLSAlignment); } else { @@ -2630,7 +2686,7 @@ struct VarArgAMD64Helper : public VarArgHelper { case AK_Memory: uint64_t ArgSize = MS.DL->getTypeAllocSize(A->getType()); Base = getShadowPtrForVAArgument(A->getType(), IRB, OverflowOffset); - OverflowOffset += DataLayout::RoundUpAlignment(ArgSize, 8); + OverflowOffset += RoundUpToAlignment(ArgSize, 8); } IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); }