#define DEBUG_TYPE "msan"
-static const uint64_t kShadowMask32 = 1ULL << 31;
-static const uint64_t kShadowMask64 = 1ULL << 46;
-static const uint64_t kOriginOffset32 = 1ULL << 30;
-static const uint64_t kOriginOffset64 = 1ULL << 45;
static const unsigned kMinOriginAlignment = 4;
static const unsigned kShadowTLSAlignment = 8;
"inline checks (-1 means never use callbacks)."),
cl::Hidden, cl::init(3500));
-// Experimental. Wraps all indirect calls in the instrumented code with
-// a call to the given function. This is needed to assist the dynamic
-// helper tool (MSanDR) to regain control on transition between instrumented and
-// non-instrumented code.
-static cl::opt<std::string> ClWrapIndirectCalls("msan-wrap-indirect-calls",
- cl::desc("Wrap indirect calls with a given function"),
- cl::Hidden);
-
-static cl::opt<bool> 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.
namespace {
+// Memory map parameters used in application-to-shadow address calculation.
+// Offset = (Addr & ~AndMask) ^ XorMask
+// Shadow = ShadowBase + Offset
+// Origin = OriginBase + Offset
+struct MemoryMapParams {
+ uint64_t AndMask;
+ uint64_t XorMask;
+ uint64_t ShadowBase;
+ uint64_t OriginBase;
+};
+
+struct PlatformMemoryMapParams {
+ const MemoryMapParams *bits32;
+ const MemoryMapParams *bits64;
+};
+
+// i386 Linux
+static const MemoryMapParams LinuxMemoryMapParams32 = {
+ 0x000080000000, // AndMask
+ 0, // XorMask (not used)
+ 0, // ShadowBase (not used)
+ 0x000040000000, // OriginBase
+};
+
+// x86_64 Linux
+static const MemoryMapParams LinuxMemoryMapParams64 = {
+ 0x400000000000, // AndMask
+ 0, // XorMask (not used)
+ 0, // ShadowBase (not used)
+ 0x200000000000, // OriginBase
+};
+
+// i386 FreeBSD
+static const MemoryMapParams FreeBSDMemoryMapParams32 = {
+ 0x000180000000, // AndMask
+ 0x000040000000, // XorMask
+ 0x000020000000, // ShadowBase
+ 0x000700000000, // OriginBase
+};
+
+// x86_64 FreeBSD
+static const MemoryMapParams FreeBSDMemoryMapParams64 = {
+ 0xc00000000000, // AndMask
+ 0x200000000000, // XorMask
+ 0x100000000000, // ShadowBase
+ 0x380000000000, // OriginBase
+};
+
+static const PlatformMemoryMapParams LinuxMemoryMapParams = {
+ &LinuxMemoryMapParams32,
+ &LinuxMemoryMapParams64,
+};
+
+static const PlatformMemoryMapParams FreeBSDMemoryMapParams = {
+ &FreeBSDMemoryMapParams32,
+ &FreeBSDMemoryMapParams64,
+};
+
/// \brief An instrumentation pass implementing detection of uninitialized
/// reads.
///
: FunctionPass(ID),
TrackOrigins(std::max(TrackOrigins, (int)ClTrackOrigins)),
DL(nullptr),
- WarningFn(nullptr),
- WrapIndirectCalls(!ClWrapIndirectCalls.empty()) {}
+ WarningFn(nullptr) {}
const char *getPassName() const override { return "MemorySanitizer"; }
bool runOnFunction(Function &F) override;
bool doInitialization(Module &M) override;
/// function.
GlobalVariable *OriginTLS;
- GlobalVariable *MsandrModuleStart;
- GlobalVariable *MsandrModuleEnd;
-
/// \brief The run-time callback to print a warning.
Value *WarningFn;
// These arrays are indexed by log2(AccessSize).
/// \brief MSan runtime replacements for memmove, memcpy and memset.
Value *MemmoveFn, *MemcpyFn, *MemsetFn;
- /// \brief Address mask used in application-to-shadow address calculation.
- /// ShadowAddr is computed as ApplicationAddr & ~ShadowMask.
- uint64_t ShadowMask;
- /// \brief Offset of the origin shadow from the "normal" shadow.
- /// OriginAddr is computed as (ShadowAddr + OriginOffset) & ~3ULL
- uint64_t OriginOffset;
- /// \brief Branch weights for error reporting.
+ /// \brief Memory map parameters used in application-to-shadow calculation.
+ const MemoryMapParams *MapParams;
+
MDNode *ColdCallWeights;
/// \brief Branch weights for origin store.
MDNode *OriginStoreWeights;
/// \brief An empty volatile inline asm that prevents callback merge.
InlineAsm *EmptyAsm;
- bool WrapIndirectCalls;
- /// \brief Run-time wrapper for indirect calls.
- Value *IndirectCallWrapperFn;
- // Argument and return type of IndirectCallWrapperFn: void (*f)(void).
- Type *AnyFunctionPtrTy;
-
friend struct MemorySanitizerVisitor;
friend struct VarArgAMD64Helper;
};
MsanSetAllocaOrigin4Fn = M.getOrInsertFunction(
"__msan_set_alloca_origin4", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy,
IRB.getInt8PtrTy(), IntptrTy, nullptr);
- MsanPoisonStackFn = M.getOrInsertFunction(
- "__msan_poison_stack", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy, nullptr);
+ MsanPoisonStackFn =
+ M.getOrInsertFunction("__msan_poison_stack", IRB.getVoidTy(),
+ IRB.getInt8PtrTy(), IntptrTy, nullptr);
MsanChainOriginFn = M.getOrInsertFunction(
"__msan_chain_origin", IRB.getInt32Ty(), IRB.getInt32Ty(), nullptr);
MemmoveFn = M.getOrInsertFunction(
EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false),
StringRef(""), StringRef(""),
/*hasSideEffects=*/true);
-
- if (WrapIndirectCalls) {
- AnyFunctionPtrTy =
- PointerType::getUnqual(FunctionType::get(IRB.getVoidTy(), false));
- IndirectCallWrapperFn = M.getOrInsertFunction(
- ClWrapIndirectCalls, AnyFunctionPtrTy, AnyFunctionPtrTy, nullptr);
- }
-
- if (WrapIndirectCalls && ClWrapIndirectCallsFast) {
- MsandrModuleStart = new GlobalVariable(
- M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage,
- nullptr, "__executable_start");
- MsandrModuleStart->setVisibility(GlobalVariable::HiddenVisibility);
- MsandrModuleEnd = new GlobalVariable(
- M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage,
- nullptr, "_end");
- MsandrModuleEnd->setVisibility(GlobalVariable::HiddenVisibility);
- }
}
/// \brief Module-level initialization.
report_fatal_error("data layout missing");
DL = &DLP->getDataLayout();
+ Triple TargetTriple(M.getTargetTriple());
+ const PlatformMemoryMapParams *PlatformMapParams;
+ if (TargetTriple.getOS() == Triple::FreeBSD)
+ PlatformMapParams = &FreeBSDMemoryMapParams;
+ else
+ PlatformMapParams = &LinuxMemoryMapParams;
+
C = &(M.getContext());
unsigned PtrSize = DL->getPointerSizeInBits(/* AddressSpace */0);
switch (PtrSize) {
case 64:
- ShadowMask = kShadowMask64;
- OriginOffset = kOriginOffset64;
+ MapParams = PlatformMapParams->bits64;
break;
case 32:
- ShadowMask = kShadowMask32;
- OriginOffset = kOriginOffset32;
+ MapParams = PlatformMapParams->bits32;
break;
default:
report_fatal_error("unsupported pointer size");
};
SmallVector<ShadowOriginAndInsertPoint, 16> InstrumentationList;
SmallVector<Instruction*, 16> StoreList;
- SmallVector<CallSite, 16> IndirectCallList;
MemorySanitizerVisitor(Function &F, MemorySanitizer &MS)
: F(F), MS(MS), VAHelper(CreateVarArgHelper(F, MS, *this)) {
void storeOrigin(IRBuilder<> &IRB, Value *Addr, Value *Shadow, Value *Origin,
unsigned Alignment, bool AsCall) {
+ unsigned OriginAlignment = std::max(kMinOriginAlignment, Alignment);
if (isa<StructType>(Shadow->getType())) {
- IRB.CreateAlignedStore(updateOrigin(Origin, IRB), getOriginPtr(Addr, IRB),
- Alignment);
+ IRB.CreateAlignedStore(updateOrigin(Origin, IRB),
+ getOriginPtr(Addr, IRB, Alignment),
+ OriginAlignment);
} else {
Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB);
// TODO(eugenis): handle non-zero constant shadow by inserting an
Cmp, IRB.GetInsertPoint(), false, MS.OriginStoreWeights);
IRBuilder<> IRBNew(CheckTerm);
IRBNew.CreateAlignedStore(updateOrigin(Origin, IRBNew),
- getOriginPtr(Addr, IRBNew), Alignment);
+ getOriginPtr(Addr, IRBNew, Alignment),
+ OriginAlignment);
}
}
}
if (SI.isAtomic()) SI.setOrdering(addReleaseOrdering(SI.getOrdering()));
- if (MS.TrackOrigins) {
- unsigned Alignment = std::max(kMinOriginAlignment, SI.getAlignment());
- storeOrigin(IRB, Addr, Shadow, getOrigin(Val), Alignment,
+ if (MS.TrackOrigins)
+ storeOrigin(IRB, Addr, Shadow, getOrigin(Val), SI.getAlignment(),
InstrumentWithCalls);
- }
}
}
DEBUG(dbgs() << "DONE:\n" << F);
}
- void materializeIndirectCalls() {
- for (auto &CS : IndirectCallList) {
- Instruction *I = CS.getInstruction();
- BasicBlock *B = I->getParent();
- IRBuilder<> IRB(I);
- Value *Fn0 = CS.getCalledValue();
- Value *Fn = IRB.CreateBitCast(Fn0, MS.AnyFunctionPtrTy);
-
- if (ClWrapIndirectCallsFast) {
- // Check that call target is inside this module limits.
- Value *Start =
- IRB.CreateBitCast(MS.MsandrModuleStart, MS.AnyFunctionPtrTy);
- Value *End = IRB.CreateBitCast(MS.MsandrModuleEnd, MS.AnyFunctionPtrTy);
-
- Value *NotInThisModule = IRB.CreateOr(IRB.CreateICmpULT(Fn, Start),
- IRB.CreateICmpUGE(Fn, End));
-
- PHINode *NewFnPhi =
- IRB.CreatePHI(Fn0->getType(), 2, "msandr.indirect_target");
-
- Instruction *CheckTerm = SplitBlockAndInsertIfThen(
- NotInThisModule, NewFnPhi,
- /* Unreachable */ false, MS.ColdCallWeights);
-
- IRB.SetInsertPoint(CheckTerm);
- // Slow path: call wrapper function to possibly transform the call
- // target.
- Value *NewFn = IRB.CreateBitCast(
- IRB.CreateCall(MS.IndirectCallWrapperFn, Fn), Fn0->getType());
-
- NewFnPhi->addIncoming(Fn0, B);
- NewFnPhi->addIncoming(NewFn, dyn_cast<Instruction>(NewFn)->getParent());
- CS.setCalledFunction(NewFnPhi);
- } else {
- Value *NewFn = IRB.CreateBitCast(
- IRB.CreateCall(MS.IndirectCallWrapperFn, Fn), Fn0->getType());
- CS.setCalledFunction(NewFn);
- }
- }
- }
-
/// \brief Add MemorySanitizer instrumentation to a function.
bool runOnFunction() {
MS.initializeCallbacks(*F.getParent());
// Insert shadow value checks.
materializeChecks(InstrumentWithCalls);
- // Wrap indirect calls.
- materializeIndirectCalls();
-
return true;
}
return IRB.CreateBitCast(V, NoVecTy);
}
+ /// \brief Compute the integer shadow offset that corresponds to a given
+ /// application address.
+ ///
+ /// Offset = (Addr & ~AndMask) ^ XorMask
+ Value *getShadowPtrOffset(Value *Addr, IRBuilder<> &IRB) {
+ uint64_t AndMask = MS.MapParams->AndMask;
+ assert(AndMask != 0 && "AndMask shall be specified");
+ Value *OffsetLong =
+ IRB.CreateAnd(IRB.CreatePointerCast(Addr, MS.IntptrTy),
+ ConstantInt::get(MS.IntptrTy, ~AndMask));
+
+ uint64_t XorMask = MS.MapParams->XorMask;
+ if (XorMask != 0)
+ OffsetLong = IRB.CreateXor(OffsetLong,
+ ConstantInt::get(MS.IntptrTy, XorMask));
+ return OffsetLong;
+ }
+
/// \brief Compute the shadow address that corresponds to a given application
/// address.
///
- /// Shadow = Addr & ~ShadowMask.
+ /// Shadow = ShadowBase + Offset
Value *getShadowPtr(Value *Addr, Type *ShadowTy,
IRBuilder<> &IRB) {
- Value *ShadowLong =
- IRB.CreateAnd(IRB.CreatePointerCast(Addr, MS.IntptrTy),
- ConstantInt::get(MS.IntptrTy, ~MS.ShadowMask));
+ Value *ShadowLong = getShadowPtrOffset(Addr, IRB);
+ uint64_t ShadowBase = MS.MapParams->ShadowBase;
+ if (ShadowBase != 0)
+ ShadowLong =
+ IRB.CreateAdd(ShadowLong,
+ ConstantInt::get(MS.IntptrTy, ShadowBase));
return IRB.CreateIntToPtr(ShadowLong, PointerType::get(ShadowTy, 0));
}
/// \brief Compute the origin address that corresponds to a given application
/// address.
///
- /// OriginAddr = (ShadowAddr + OriginOffset) & ~3ULL
- Value *getOriginPtr(Value *Addr, IRBuilder<> &IRB) {
- Value *ShadowLong =
- IRB.CreateAnd(IRB.CreatePointerCast(Addr, MS.IntptrTy),
- ConstantInt::get(MS.IntptrTy, ~MS.ShadowMask));
- Value *Add =
- IRB.CreateAdd(ShadowLong,
- ConstantInt::get(MS.IntptrTy, MS.OriginOffset));
- Value *SecondAnd =
- IRB.CreateAnd(Add, ConstantInt::get(MS.IntptrTy, ~3ULL));
- return IRB.CreateIntToPtr(SecondAnd, PointerType::get(IRB.getInt32Ty(), 0));
+ /// OriginAddr = (OriginBase + Offset) & ~3ULL
+ Value *getOriginPtr(Value *Addr, IRBuilder<> &IRB, unsigned Alignment) {
+ Value *OriginLong = getShadowPtrOffset(Addr, IRB);
+ uint64_t OriginBase = MS.MapParams->OriginBase;
+ if (OriginBase != 0)
+ OriginLong =
+ IRB.CreateAdd(OriginLong,
+ ConstantInt::get(MS.IntptrTy, OriginBase));
+ if (Alignment < kMinOriginAlignment) {
+ uint64_t Mask = kMinOriginAlignment - 1;
+ OriginLong = IRB.CreateAnd(OriginLong,
+ ConstantInt::get(MS.IntptrTy, ~Mask));
+ }
+ return IRB.CreateIntToPtr(OriginLong,
+ PointerType::get(IRB.getInt32Ty(), 0));
}
/// \brief Compute the shadow address for a given function argument.
Value *OriginPtr =
getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset);
setOrigin(A, EntryIRB.CreateLoad(OriginPtr));
+ } else {
+ setOrigin(A, getCleanOrigin());
}
}
ArgOffset += RoundUpToAlignment(Size, kShadowTLSAlignment);
/// \brief Get the origin for a value.
Value *getOrigin(Value *V) {
if (!MS.TrackOrigins) return nullptr;
- if (isa<Instruction>(V) || isa<Argument>(V)) {
- Value *Origin = OriginMap[V];
- if (!Origin) {
- DEBUG(dbgs() << "NO ORIGIN: " << *V << "\n");
- Origin = getCleanOrigin();
- }
- return Origin;
- }
- return getCleanOrigin();
+ if (!PropagateShadow) return getCleanOrigin();
+ if (isa<Constant>(V)) return getCleanOrigin();
+ assert((isa<Instruction>(V) || isa<Argument>(V)) &&
+ "Unexpected value type in getOrigin()");
+ Value *Origin = OriginMap[V];
+ assert(Origin && "Missing origin");
+ return Origin;
}
/// \brief Get the origin for i-th argument of the instruction I.
IRBuilder<> IRB(I.getNextNode());
Type *ShadowTy = getShadowTy(&I);
Value *Addr = I.getPointerOperand();
- if (PropagateShadow) {
+ if (PropagateShadow && !I.getMetadata("nosanitize")) {
Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
setShadow(&I,
IRB.CreateAlignedLoad(ShadowPtr, I.getAlignment(), "_msld"));
if (MS.TrackOrigins) {
if (PropagateShadow) {
- unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
- setOrigin(&I,
- IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB), Alignment));
+ unsigned Alignment = I.getAlignment();
+ unsigned OriginAlignment = std::max(kMinOriginAlignment, Alignment);
+ setOrigin(&I, IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB, Alignment),
+ OriginAlignment));
} else {
setOrigin(&I, getCleanOrigin());
}
IRB.CreateStore(getCleanShadow(&I), ShadowPtr);
setShadow(&I, getCleanShadow(&I));
+ setOrigin(&I, getCleanOrigin());
}
void visitAtomicRMWInst(AtomicRMWInst &I) {
// FIXME: use ClStoreCleanOrigin
// FIXME: factor out common code from materializeStores
if (MS.TrackOrigins)
- IRB.CreateStore(getOrigin(&I, 1), getOriginPtr(Addr, IRB));
+ IRB.CreateStore(getOrigin(&I, 1), getOriginPtr(Addr, IRB, 1));
return true;
}
if (MS.TrackOrigins) {
if (PropagateShadow)
- setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB)));
+ setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB, 1)));
else
setOrigin(&I, getCleanOrigin());
}
setOrigin(&I, getOrigin(CopyOp));
} else {
setShadow(&I, getCleanShadow(&I));
+ setOrigin(&I, getCleanOrigin());
}
}
}
IRBuilder<> IRB(&I);
- if (MS.WrapIndirectCalls && !CS.getCalledFunction())
- IndirectCallList.push_back(CS);
-
unsigned ArgOffset = 0;
DEBUG(dbgs() << " CallSite: " << I << "\n");
for (CallSite::arg_iterator ArgIt = CS.arg_begin(), End = CS.arg_end();
IRBuilder<> IRB(&I);
if (!PropagateShadow) {
setShadow(&I, getCleanShadow(&I));
+ setOrigin(&I, getCleanOrigin());
return;
}
void visitAllocaInst(AllocaInst &I) {
setShadow(&I, getCleanShadow(&I));
+ setOrigin(&I, getCleanOrigin());
IRBuilder<> IRB(I.getNextNode());
uint64_t Size = MS.DL->getTypeAllocSize(I.getAllocatedType());
if (PoisonStack && ClPoisonStackWithCall) {
}
if (PoisonStack && MS.TrackOrigins) {
- setOrigin(&I, getCleanOrigin());
SmallString<2048> StackDescriptionStorage;
raw_svector_ostream StackDescription(StackDescriptionStorage);
// We create a string with a description of the stack allocation and
}
// a = select b, c, d
// Oa = Sb ? Ob : (b ? Oc : Od)
- setOrigin(&I, IRB.CreateSelect(
- Sb, getOrigin(I.getCondition()),
- IRB.CreateSelect(B, getOrigin(C), getOrigin(D))));
+ setOrigin(
+ &I, IRB.CreateSelect(Sb, getOrigin(I.getCondition()),
+ IRB.CreateSelect(B, getOrigin(I.getTrueValue()),
+ getOrigin(I.getFalseValue()))));
}
}