[llvm] r341637 - [MSan] Add KMSAN instrumentation to MSan pass
Alexander Potapenko via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 7 02:10:30 PDT 2018
Author: glider
Date: Fri Sep 7 02:10:30 2018
New Revision: 341637
URL: http://llvm.org/viewvc/llvm-project?rev=341637&view=rev
Log:
[MSan] Add KMSAN instrumentation to MSan pass
Introduce the -msan-kernel flag, which enables the kernel instrumentation.
The main differences between KMSAN and MSan instrumentations are:
- KMSAN implies msan-track-origins=2, msan-keep-going=true;
- there're no explicit accesses to shadow and origin memory.
Shadow and origin values for a particular X-byte memory location are
read and written via pointers returned by
__msan_metadata_ptr_for_load_X(u8 *addr) and
__msan_store_shadow_origin_X(u8 *addr, uptr shadow, uptr origin);
- TLS variables are stored in a single struct in per-task storage. A call
to a function returning that struct is inserted into every instrumented
function before the entry block;
- __msan_warning() takes a 32-bit origin parameter;
- local variables are poisoned with __msan_poison_alloca() upon function
entry and unpoisoned with __msan_unpoison_alloca() before leaving the
function;
- the pass doesn't declare any global variables or add global constructors
to the translation unit.
Added:
llvm/trunk/test/Instrumentation/MemorySanitizer/msan_kernel_basic.ll
Modified:
llvm/trunk/include/llvm/Transforms/Instrumentation.h
llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp
llvm/trunk/test/Instrumentation/MemorySanitizer/alloca.ll
llvm/trunk/test/Instrumentation/MemorySanitizer/store-origin.ll
Modified: llvm/trunk/include/llvm/Transforms/Instrumentation.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Instrumentation.h?rev=341637&r1=341636&r2=341637&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Instrumentation.h (original)
+++ llvm/trunk/include/llvm/Transforms/Instrumentation.h Fri Sep 7 02:10:30 2018
@@ -134,7 +134,8 @@ ModulePass *createAddressSanitizerModule
// Insert MemorySanitizer instrumentation (detection of uninitialized reads)
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0,
- bool Recover = false);
+ bool Recover = false,
+ bool EnableKmsan = false);
FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false,
bool Recover = false);
Modified: llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp?rev=341637&r1=341636&r2=341637&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/MemorySanitizer.cpp Fri Sep 7 02:10:30 2018
@@ -89,7 +89,38 @@
/// implementation ignores the load aspect of CAS/RMW, always returning a clean
/// value. It implements the store part as a simple atomic store by storing a
/// clean shadow.
-//
+///
+/// KernelMemorySanitizer (KMSAN) implementation.
+///
+/// The major differences between KMSAN and MSan instrumentation are:
+/// - KMSAN always tracks the origins and implies msan-keep-going=true;
+/// - KMSAN allocates shadow and origin memory for each page separately, so
+/// there are no explicit accesses to shadow and origin in the
+/// instrumentation.
+/// Shadow and origin values for a particular X-byte memory location
+/// (X=1,2,4,8) are accessed through pointers obtained via the
+/// __msan_metadata_ptr_for_load_X(ptr)
+/// __msan_metadata_ptr_for_store_X(ptr)
+/// functions. The corresponding functions check that the X-byte accesses
+/// are possible and returns the pointers to shadow and origin memory.
+/// Arbitrary sized accesses are handled with:
+/// __msan_metadata_ptr_for_load_n(ptr, size)
+/// __msan_metadata_ptr_for_store_n(ptr, size);
+/// - TLS variables are stored in a single per-task struct. A call to a
+/// function __msan_get_context_state() returning a pointer to that struct
+/// is inserted into every instrumented function before the entry block;
+/// - __msan_warning() takes a 32-bit origin parameter;
+/// - local variables are poisoned with __msan_poison_alloca() upon function
+/// entry and unpoisoned with __msan_unpoison_alloca() before leaving the
+/// function;
+/// - the pass doesn't declare any global variables or add global constructors
+/// to the translation unit.
+///
+/// Also, KMSAN currently ignores uninitialized memory passed into inline asm
+/// calls, making sure we're on the safe side wrt. possible false positives.
+///
+/// KernelMemorySanitizer only supports X86_64 at the moment.
+///
//===----------------------------------------------------------------------===//
#include "llvm/ADT/APInt.h"
@@ -233,6 +264,11 @@ static cl::opt<int> ClInstrumentationWit
"inline checks (-1 means never use callbacks)."),
cl::Hidden, cl::init(3500));
+static cl::opt<bool>
+ ClEnableKmsan("msan-kernel",
+ cl::desc("Enable KernelMemorySanitizer instrumentation"),
+ cl::Hidden, cl::init(false));
+
// 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.
@@ -400,11 +436,19 @@ public:
// Pass identification, replacement for typeid.
static char ID;
- MemorySanitizer(int TrackOrigins = 0, bool Recover = false)
- : FunctionPass(ID),
- TrackOrigins(std::max(TrackOrigins, (int)ClTrackOrigins)),
- Recover(Recover || ClKeepGoing) {}
-
+ MemorySanitizer(int TrackOrigins = 0, bool Recover = false,
+ bool EnableKmsan = false)
+ : FunctionPass(ID) {
+ this->CompileKernel =
+ ClEnableKmsan.getNumOccurrences() > 0 ? ClEnableKmsan : EnableKmsan;
+ if (ClTrackOrigins.getNumOccurrences() > 0)
+ this->TrackOrigins = ClTrackOrigins;
+ else
+ this->TrackOrigins = this->CompileKernel ? 2 : TrackOrigins;
+ this->Recover = ClKeepGoing.getNumOccurrences() > 0
+ ? ClKeepGoing
+ : (this->CompileKernel | Recover);
+ }
StringRef getPassName() const override { return "MemorySanitizer"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -422,8 +466,12 @@ private:
friend struct VarArgPowerPC64Helper;
void initializeCallbacks(Module &M);
+ void createKernelApi(Module &M);
void createUserspaceApi(Module &M);
+ /// True if we're compiling the Linux kernel.
+ bool CompileKernel;
+
/// Track origins (allocation points) of uninitialized values.
int TrackOrigins;
bool Recover;
@@ -432,33 +480,39 @@ private:
Type *IntptrTy;
Type *OriginTy;
+ // XxxTLS variables represent the per-thread state in MSan and per-task state
+ // in KMSAN.
+ // For the userspace these point to thread-local globals. In the kernel land
+ // they point to the members of a per-task struct obtained via a call to
+ // __msan_get_context_state().
+
/// Thread-local shadow storage for function parameters.
- GlobalVariable *ParamTLS;
+ Value *ParamTLS;
/// Thread-local origin storage for function parameters.
- GlobalVariable *ParamOriginTLS;
+ Value *ParamOriginTLS;
/// Thread-local shadow storage for function return value.
- GlobalVariable *RetvalTLS;
+ Value *RetvalTLS;
/// Thread-local origin storage for function return value.
- GlobalVariable *RetvalOriginTLS;
+ Value *RetvalOriginTLS;
/// Thread-local shadow storage for in-register va_arg function
/// parameters (x86_64-specific).
- GlobalVariable *VAArgTLS;
+ Value *VAArgTLS;
/// Thread-local shadow storage for in-register va_arg function
/// parameters (x86_64-specific).
- GlobalVariable *VAArgOriginTLS;
+ Value *VAArgOriginTLS;
/// Thread-local shadow storage for va_arg overflow area
/// (x86_64-specific).
- GlobalVariable *VAArgOverflowSizeTLS;
+ Value *VAArgOverflowSizeTLS;
/// Thread-local space used to pass origin value to the UMR reporting
/// function.
- GlobalVariable *OriginTLS;
+ Value *OriginTLS;
/// Are the instrumentation callbacks set up?
bool CallbacksInitialized = false;
@@ -484,6 +538,21 @@ private:
/// MSan runtime replacements for memmove, memcpy and memset.
Value *MemmoveFn, *MemcpyFn, *MemsetFn;
+ /// KMSAN callback for task-local function argument shadow.
+ Value *MsanGetContextStateFn;
+
+ /// Functions for poisoning/unpoisoning local variables
+ Value *MsanPoisonAllocaFn, *MsanUnpoisonAllocaFn;
+
+ /// Each of the MsanMetadataPtrXxx functions returns a pair of shadow/origin
+ /// pointers.
+ Value *MsanMetadataPtrForLoadN, *MsanMetadataPtrForStoreN;
+ Value *MsanMetadataPtrForLoad_1_8[4];
+ Value *MsanMetadataPtrForStore_1_8[4];
+
+ /// Helper to choose between different MsanMetadataPtrXxx().
+ Value *getKmsanShadowOriginAccessFn(bool isStore, int size);
+
/// Memory map parameters used in application-to-shadow calculation.
const MemoryMapParams *MapParams;
@@ -514,8 +583,9 @@ INITIALIZE_PASS_END(
MemorySanitizer, "msan",
"MemorySanitizer: detects uninitialized reads.", false, false)
-FunctionPass *llvm::createMemorySanitizerPass(int TrackOrigins, bool Recover) {
- return new MemorySanitizer(TrackOrigins, Recover);
+FunctionPass *llvm::createMemorySanitizerPass(int TrackOrigins, bool Recover,
+ bool CompileKernel) {
+ return new MemorySanitizer(TrackOrigins, Recover, CompileKernel);
}
/// Create a non-const global initialized with the given string.
@@ -530,6 +600,68 @@ static GlobalVariable *createPrivateNonC
GlobalValue::PrivateLinkage, StrConst, "");
}
+/// Create KMSAN API callbacks.
+void MemorySanitizer::createKernelApi(Module &M) {
+ IRBuilder<> IRB(*C);
+
+ // These will be initialized in insertKmsanPrologue().
+ RetvalTLS = nullptr;
+ RetvalOriginTLS = nullptr;
+ ParamTLS = nullptr;
+ ParamOriginTLS = nullptr;
+ VAArgTLS = nullptr;
+ VAArgOriginTLS = nullptr;
+ VAArgOverflowSizeTLS = nullptr;
+ // OriginTLS is unused in the kernel.
+ OriginTLS = nullptr;
+
+ // __msan_warning() in the kernel takes an origin.
+ WarningFn = M.getOrInsertFunction("__msan_warning", IRB.getVoidTy(),
+ IRB.getInt32Ty());
+ // Requests the per-task context state (kmsan_context_state*) from the
+ // runtime library.
+ MsanGetContextStateFn = M.getOrInsertFunction(
+ "__msan_get_context_state",
+ PointerType::get(
+ StructType::get(ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8),
+ ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8),
+ ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8),
+ ArrayType::get(IRB.getInt64Ty(),
+ kParamTLSSize / 8), /* va_arg_origin */
+ IRB.getInt64Ty(),
+ ArrayType::get(OriginTy, kParamTLSSize / 4), OriginTy,
+ OriginTy),
+ 0));
+
+ Type *RetTy = StructType::get(PointerType::get(IRB.getInt8Ty(), 0),
+ PointerType::get(IRB.getInt32Ty(), 0));
+
+ for (int ind = 0, size = 1; ind < 4; ind++, size <<= 1) {
+ std::string name_load =
+ "__msan_metadata_ptr_for_load_" + std::to_string(size);
+ std::string name_store =
+ "__msan_metadata_ptr_for_store_" + std::to_string(size);
+ MsanMetadataPtrForLoad_1_8[ind] = M.getOrInsertFunction(
+ name_load, RetTy, PointerType::get(IRB.getInt8Ty(), 0));
+ MsanMetadataPtrForStore_1_8[ind] = M.getOrInsertFunction(
+ name_store, RetTy, PointerType::get(IRB.getInt8Ty(), 0));
+ }
+
+ MsanMetadataPtrForLoadN = M.getOrInsertFunction(
+ "__msan_metadata_ptr_for_load_n", RetTy,
+ PointerType::get(IRB.getInt8Ty(), 0), IRB.getInt64Ty());
+ MsanMetadataPtrForStoreN = M.getOrInsertFunction(
+ "__msan_metadata_ptr_for_store_n", RetTy,
+ PointerType::get(IRB.getInt8Ty(), 0), IRB.getInt64Ty());
+
+ // Functions for poisoning and unpoisoning memory.
+ MsanPoisonAllocaFn =
+ M.getOrInsertFunction("__msan_poison_alloca", IRB.getVoidTy(),
+ IRB.getInt8PtrTy(), IntptrTy, IRB.getInt8PtrTy());
+ MsanUnpoisonAllocaFn = M.getOrInsertFunction(
+ "__msan_unpoison_alloca", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy);
+}
+
/// Insert declarations for userspace-specific functions and globals.
void MemorySanitizer::createUserspaceApi(Module &M) {
IRBuilder<> IRB(*C);
@@ -625,10 +757,31 @@ void MemorySanitizer::initializeCallback
StringRef(""), StringRef(""),
/*hasSideEffects=*/true);
- createUserspaceApi(M);
+ if (CompileKernel) {
+ createKernelApi(M);
+ } else {
+ createUserspaceApi(M);
+ }
CallbacksInitialized = true;
}
+Value *MemorySanitizer::getKmsanShadowOriginAccessFn(bool isStore, int size) {
+ Value **Fns =
+ isStore ? MsanMetadataPtrForStore_1_8 : MsanMetadataPtrForLoad_1_8;
+ switch (size) {
+ case 1:
+ return Fns[0];
+ case 2:
+ return Fns[1];
+ case 4:
+ return Fns[2];
+ case 8:
+ return Fns[3];
+ default:
+ return nullptr;
+ }
+}
+
/// Module-level initialization.
///
/// inserts a call to __msan_init to the module's constructor list.
@@ -705,27 +858,28 @@ bool MemorySanitizer::doInitialization(M
ColdCallWeights = MDBuilder(*C).createBranchWeights(1, 1000);
OriginStoreWeights = MDBuilder(*C).createBranchWeights(1, 1000);
- std::tie(MsanCtorFunction, std::ignore) =
- createSanitizerCtorAndInitFunctions(M, kMsanModuleCtorName, kMsanInitName,
- /*InitArgTypes=*/{},
- /*InitArgs=*/{});
- if (ClWithComdat) {
- Comdat *MsanCtorComdat = M.getOrInsertComdat(kMsanModuleCtorName);
- MsanCtorFunction->setComdat(MsanCtorComdat);
- appendToGlobalCtors(M, MsanCtorFunction, 0, MsanCtorFunction);
- } else {
- appendToGlobalCtors(M, MsanCtorFunction, 0);
- }
-
-
- if (TrackOrigins)
- new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage,
- IRB.getInt32(TrackOrigins), "__msan_track_origins");
+ if (!CompileKernel) {
+ std::tie(MsanCtorFunction, std::ignore) =
+ createSanitizerCtorAndInitFunctions(M, kMsanModuleCtorName,
+ kMsanInitName,
+ /*InitArgTypes=*/{},
+ /*InitArgs=*/{});
+ if (ClWithComdat) {
+ Comdat *MsanCtorComdat = M.getOrInsertComdat(kMsanModuleCtorName);
+ MsanCtorFunction->setComdat(MsanCtorComdat);
+ appendToGlobalCtors(M, MsanCtorFunction, 0, MsanCtorFunction);
+ } else {
+ appendToGlobalCtors(M, MsanCtorFunction, 0);
+ }
- if (Recover)
- new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage,
- IRB.getInt32(Recover), "__msan_keep_going");
+ if (TrackOrigins)
+ new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage,
+ IRB.getInt32(TrackOrigins), "__msan_track_origins");
+ if (Recover)
+ new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage,
+ IRB.getInt32(Recover), "__msan_keep_going");
+ }
return true;
}
@@ -819,7 +973,10 @@ struct MemorySanitizerVisitor : public I
TLI = &MS.getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
MS.initializeCallbacks(*F.getParent());
- ActualFnStart = &F.getEntryBlock();
+ if (MS.CompileKernel)
+ ActualFnStart = insertKmsanPrologue(F);
+ else
+ ActualFnStart = &F.getEntryBlock();
LLVM_DEBUG(if (!InsertChecks) dbgs()
<< "MemorySanitizer is not inserting checks into '"
@@ -893,7 +1050,7 @@ struct MemorySanitizerVisitor : public I
unsigned TypeSizeInBits =
DL.getTypeSizeInBits(ConvertedShadow->getType());
unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits);
- if (AsCall && SizeIndex < kNumberOfAccessSizes) {
+ if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) {
Value *Fn = MS.MaybeStoreOriginFn[SizeIndex];
Value *ConvertedShadow2 = IRB.CreateZExt(
ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex)));
@@ -942,10 +1099,14 @@ struct MemorySanitizerVisitor : public I
void insertWarningFn(IRBuilder<> &IRB, Value *Origin) {
if (!Origin)
Origin = (Value *)IRB.getInt32(0);
- if (MS.TrackOrigins) {
- IRB.CreateStore(Origin, MS.OriginTLS);
+ if (MS.CompileKernel) {
+ IRB.CreateCall(MS.WarningFn, Origin);
+ } else {
+ if (MS.TrackOrigins) {
+ IRB.CreateStore(Origin, MS.OriginTLS);
+ }
+ IRB.CreateCall(MS.WarningFn, {});
}
- IRB.CreateCall(MS.WarningFn, {});
IRB.CreateCall(MS.EmptyAsm, {});
// FIXME: Insert UnreachableInst if !MS.Recover?
// This may invalidate some of the following checks and needs to be done
@@ -971,7 +1132,7 @@ struct MemorySanitizerVisitor : public I
unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType());
unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits);
- if (AsCall && SizeIndex < kNumberOfAccessSizes) {
+ if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) {
Value *Fn = MS.MaybeWarningFn[SizeIndex];
Value *ConvertedShadow2 =
IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex)));
@@ -1001,6 +1162,29 @@ struct MemorySanitizerVisitor : public I
LLVM_DEBUG(dbgs() << "DONE:\n" << F);
}
+ BasicBlock *insertKmsanPrologue(Function &F) {
+ BasicBlock *ret =
+ SplitBlock(&F.getEntryBlock(), F.getEntryBlock().getFirstNonPHI());
+ IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
+ Value *ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {});
+ Constant *Zero = IRB.getInt32(0);
+ MS.ParamTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(0)}, "param_shadow");
+ MS.RetvalTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(1)}, "retval_shadow");
+ MS.VAArgTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(2)}, "va_arg_shadow");
+ MS.VAArgOriginTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(3)}, "va_arg_origin");
+ MS.VAArgOverflowSizeTLS = IRB.CreateGEP(
+ ContextState, {Zero, IRB.getInt32(4)}, "va_arg_overflow_size");
+ MS.ParamOriginTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(5)}, "param_origin");
+ MS.RetvalOriginTLS =
+ IRB.CreateGEP(ContextState, {Zero, IRB.getInt32(6)}, "retval_origin");
+ return ret;
+ }
+
/// Add MemorySanitizer instrumentation to a function.
bool runOnFunction() {
// In the presence of unreachable blocks, we may see Phi nodes with
@@ -1149,12 +1333,40 @@ struct MemorySanitizerVisitor : public I
return std::make_pair(ShadowPtr, OriginPtr);
}
+ std::pair<Value *, Value *>
+ getShadowOriginPtrKernel(Value *Addr, IRBuilder<> &IRB, Type *ShadowTy,
+ unsigned Alignment, bool isStore) {
+ Value *ShadowOriginPtrs;
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ int Size = DL.getTypeStoreSize(ShadowTy);
+
+ Value *Getter = MS.getKmsanShadowOriginAccessFn(isStore, Size);
+ Value *AddrCast =
+ IRB.CreatePointerCast(Addr, PointerType::get(IRB.getInt8Ty(), 0));
+ if (Getter) {
+ ShadowOriginPtrs = IRB.CreateCall(Getter, AddrCast);
+ } else {
+ Value *SizeVal = ConstantInt::get(MS.IntptrTy, Size);
+ ShadowOriginPtrs = IRB.CreateCall(isStore ? MS.MsanMetadataPtrForStoreN
+ : MS.MsanMetadataPtrForLoadN,
+ {AddrCast, SizeVal});
+ }
+ Value *ShadowPtr = IRB.CreateExtractValue(ShadowOriginPtrs, 0);
+ ShadowPtr = IRB.CreatePointerCast(ShadowPtr, PointerType::get(ShadowTy, 0));
+ Value *OriginPtr = IRB.CreateExtractValue(ShadowOriginPtrs, 1);
+
+ return std::make_pair(ShadowPtr, OriginPtr);
+ }
+
std::pair<Value *, Value *> getShadowOriginPtr(Value *Addr, IRBuilder<> &IRB,
Type *ShadowTy,
unsigned Alignment,
bool isStore) {
- std::pair<Value *, Value *> ret =
- getShadowOriginPtrUserspace(Addr, IRB, ShadowTy, Alignment);
+ std::pair<Value *, Value *> ret;
+ if (MS.CompileKernel)
+ ret = getShadowOriginPtrKernel(Addr, IRB, ShadowTy, Alignment, isStore);
+ else
+ ret = getShadowOriginPtrUserspace(Addr, IRB, ShadowTy, Alignment);
return ret;
}
@@ -1173,7 +1385,8 @@ struct MemorySanitizerVisitor : public I
/// Compute the origin address for a given function argument.
Value *getOriginPtrForArgument(Value *A, IRBuilder<> &IRB,
int ArgOffset) {
- if (!MS.TrackOrigins) return nullptr;
+ if (!MS.TrackOrigins)
+ return nullptr;
Value *Base = IRB.CreatePointerCast(MS.ParamOriginTLS, MS.IntptrTy);
if (ArgOffset)
Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset));
@@ -1313,6 +1526,7 @@ struct MemorySanitizerVisitor : public I
getShadowOriginPtr(V, EntryIRB, EntryIRB.getInt8Ty(), ArgAlign,
/*isStore*/ true)
.first;
+ // TODO(glider): need to copy origins.
if (Overflow) {
// ParamTLS overflow.
EntryIRB.CreateMemSet(
@@ -2931,12 +3145,14 @@ struct MemorySanitizerVisitor : public I
if (ArgOffset + Size > kParamTLSSize) break;
unsigned ParamAlignment = CS.getParamAlignment(i);
unsigned Alignment = std::min(ParamAlignment, kShadowTLSAlignment);
- Value *AShadowPtr = getShadowOriginPtr(A, IRB, IRB.getInt8Ty(),
- Alignment, /*isStore*/ false)
- .first;
+ Value *AShadowPtr =
+ getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), Alignment,
+ /*isStore*/ false)
+ .first;
Store = IRB.CreateMemCpy(ArgShadowBase, Alignment, AShadowPtr,
Alignment, Size);
+ // TODO(glider): need to copy origins.
} else {
Size = DL.getTypeAllocSize(A->getType());
if (ArgOffset + Size > kParamTLSSize) break;
@@ -3043,40 +3259,34 @@ struct MemorySanitizerVisitor : public I
"_msphi_o"));
}
- void visitAllocaInst(AllocaInst &I) {
- setShadow(&I, getCleanShadow(&I));
- setOrigin(&I, getCleanOrigin());
- IRBuilder<> IRB(I.getNextNode());
- const DataLayout &DL = F.getParent()->getDataLayout();
- uint64_t TypeSize = DL.getTypeAllocSize(I.getAllocatedType());
- Value *Len = ConstantInt::get(MS.IntptrTy, TypeSize);
- if (I.isArrayAllocation())
- Len = IRB.CreateMul(Len, I.getArraySize());
+ Value *getLocalVarDescription(AllocaInst &I) {
+ SmallString<2048> StackDescriptionStorage;
+ raw_svector_ostream StackDescription(StackDescriptionStorage);
+ // We create a string with a description of the stack allocation and
+ // pass it into __msan_set_alloca_origin.
+ // It will be printed by the run-time if stack-originated UMR is found.
+ // The first 4 bytes of the string are set to '----' and will be replaced
+ // by __msan_va_arg_overflow_size_tls at the first call.
+ StackDescription << "----" << I.getName() << "@" << F.getName();
+ return createPrivateNonConstGlobalForString(*F.getParent(),
+ StackDescription.str());
+ }
+
+ void instrumentAllocaUserspace(AllocaInst &I, IRBuilder<> &IRB, Value *Len) {
if (PoisonStack && ClPoisonStackWithCall) {
IRB.CreateCall(MS.MsanPoisonStackFn,
{IRB.CreatePointerCast(&I, IRB.getInt8PtrTy()), Len});
} else {
- Value *ShadowBase = getShadowOriginPtr(&I, IRB, IRB.getInt8Ty(),
- I.getAlignment(), /*isStore*/ true)
- .first;
+ Value *ShadowBase, *OriginBase;
+ std::tie(ShadowBase, OriginBase) =
+ getShadowOriginPtr(&I, IRB, IRB.getInt8Ty(), 1, /*isStore*/ true);
Value *PoisonValue = IRB.getInt8(PoisonStack ? ClPoisonStackPattern : 0);
IRB.CreateMemSet(ShadowBase, PoisonValue, Len, I.getAlignment());
}
if (PoisonStack && MS.TrackOrigins) {
- SmallString<2048> StackDescriptionStorage;
- raw_svector_ostream StackDescription(StackDescriptionStorage);
- // We create a string with a description of the stack allocation and
- // pass it into __msan_set_alloca_origin.
- // It will be printed by the run-time if stack-originated UMR is found.
- // The first 4 bytes of the string are set to '----' and will be replaced
- // by __msan_va_arg_overflow_size_tls at the first call.
- StackDescription << "----" << I.getName() << "@" << F.getName();
- Value *Descr =
- createPrivateNonConstGlobalForString(*F.getParent(),
- StackDescription.str());
-
+ Value *Descr = getLocalVarDescription(I);
IRB.CreateCall(MS.MsanSetAllocaOrigin4Fn,
{IRB.CreatePointerCast(&I, IRB.getInt8PtrTy()), Len,
IRB.CreatePointerCast(Descr, IRB.getInt8PtrTy()),
@@ -3084,6 +3294,34 @@ struct MemorySanitizerVisitor : public I
}
}
+ void instrumentAllocaKmsan(AllocaInst &I, IRBuilder<> &IRB, Value *Len) {
+ Value *Descr = getLocalVarDescription(I);
+ if (PoisonStack) {
+ IRB.CreateCall(MS.MsanPoisonAllocaFn,
+ {IRB.CreatePointerCast(&I, IRB.getInt8PtrTy()), Len,
+ IRB.CreatePointerCast(Descr, IRB.getInt8PtrTy())});
+ } else {
+ IRB.CreateCall(MS.MsanUnpoisonAllocaFn,
+ {IRB.CreatePointerCast(&I, IRB.getInt8PtrTy()), Len});
+ }
+ }
+
+ void visitAllocaInst(AllocaInst &I) {
+ setShadow(&I, getCleanShadow(&I));
+ setOrigin(&I, getCleanOrigin());
+ IRBuilder<> IRB(I.getNextNode());
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ uint64_t TypeSize = DL.getTypeAllocSize(I.getAllocatedType());
+ Value *Len = ConstantInt::get(MS.IntptrTy, TypeSize);
+ if (I.isArrayAllocation())
+ Len = IRB.CreateMul(Len, I.getArraySize());
+
+ if (MS.CompileKernel)
+ instrumentAllocaKmsan(I, IRB, Len);
+ else
+ instrumentAllocaUserspace(I, IRB, Len);
+ }
+
void visitSelectInst(SelectInst& I) {
IRBuilder<> IRB(&I);
// a = select b, c, d
Modified: llvm/trunk/test/Instrumentation/MemorySanitizer/alloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/MemorySanitizer/alloca.ll?rev=341637&r1=341636&r2=341637&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/MemorySanitizer/alloca.ll (original)
+++ llvm/trunk/test/Instrumentation/MemorySanitizer/alloca.ll Fri Sep 7 02:10:30 2018
@@ -2,6 +2,7 @@
; RUN: opt < %s -msan -msan-check-access-address=0 -msan-poison-stack-with-call=1 -S | FileCheck %s --check-prefixes=CHECK,CALL
; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck %s --check-prefixes=CHECK,ORIGIN
; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=2 -S | FileCheck %s --check-prefixes=CHECK,ORIGIN
+; RUN: opt < %s -msan -msan-kernel=1 -S | FileCheck %s --check-prefixes=CHECK,KMSAN
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"
@@ -16,6 +17,7 @@ entry:
; INLINE: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 -1, i64 4, i1 false)
; CALL: call void @__msan_poison_stack(i8* {{.*}}, i64 4)
; ORIGIN: call void @__msan_set_alloca_origin4(i8* {{.*}}, i64 4,
+; KMSAN: call void @__msan_poison_alloca(i8* {{.*}}, i64 4,
; CHECK: ret void
@@ -31,6 +33,7 @@ l:
; INLINE: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 -1, i64 4, i1 false)
; CALL: call void @__msan_poison_stack(i8* {{.*}}, i64 4)
; ORIGIN: call void @__msan_set_alloca_origin4(i8* {{.*}}, i64 4,
+; KMSAN: call void @__msan_poison_alloca(i8* {{.*}}, i64 4,
; CHECK: ret void
define void @array() sanitize_memory {
@@ -43,6 +46,7 @@ entry:
; INLINE: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 -1, i64 20, i1 false)
; CALL: call void @__msan_poison_stack(i8* {{.*}}, i64 20)
; ORIGIN: call void @__msan_set_alloca_origin4(i8* {{.*}}, i64 20,
+; KMSAN: call void @__msan_poison_alloca(i8* {{.*}}, i64 20,
; CHECK: ret void
define void @array_non_const(i64 %cnt) sanitize_memory {
@@ -56,4 +60,20 @@ entry:
; INLINE: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 -1, i64 %[[A]], i1 false)
; CALL: call void @__msan_poison_stack(i8* {{.*}}, i64 %[[A]])
; ORIGIN: call void @__msan_set_alloca_origin4(i8* {{.*}}, i64 %[[A]],
+; KMSAN: call void @__msan_poison_alloca(i8* {{.*}}, i64 %[[A]],
; CHECK: ret void
+
+; Check that the local is unpoisoned in the absence of sanitize_memory
+define void @unpoison_local() {
+entry:
+ %x = alloca i32, i64 5, align 4
+ ret void
+}
+
+; CHECK-LABEL: define void @unpoison_local(
+; INLINE: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 0, i64 20, i1 false)
+; CALL: call void @llvm.memset.p0i8.i64(i8* align 4 {{.*}}, i8 0, i64 20, i1 false)
+; ORIGIN-NOT: call void @__msan_set_alloca_origin4(i8* {{.*}}, i64 20,
+; KMSAN: call void @__msan_unpoison_alloca(i8* {{.*}}, i64 20)
+; CHECK: ret void
+
Added: llvm/trunk/test/Instrumentation/MemorySanitizer/msan_kernel_basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/MemorySanitizer/msan_kernel_basic.ll?rev=341637&view=auto
==============================================================================
--- llvm/trunk/test/Instrumentation/MemorySanitizer/msan_kernel_basic.ll (added)
+++ llvm/trunk/test/Instrumentation/MemorySanitizer/msan_kernel_basic.ll Fri Sep 7 02:10:30 2018
@@ -0,0 +1,404 @@
+; KMSAN instrumentation tests
+; RUN: opt < %s -msan -msan-kernel=1 -S | FileCheck %s -check-prefixes=CHECK
+
+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 the instrumentation prologue.
+define void @Empty() nounwind uwtable sanitize_memory {
+entry:
+ ret void
+}
+
+; CHECK-LABEL: @Empty
+; CHECK: entry:
+; CHECK: @__msan_get_context_state()
+; %param_shadow:
+; CHECK: getelementptr {{.*}} i32 0, i32 0
+; %retval_shadow:
+; CHECK: getelementptr {{.*}} i32 0, i32 1
+; %va_arg_shadow:
+; CHECK: getelementptr {{.*}} i32 0, i32 2
+; %va_arg_origin:
+; CHECK: getelementptr {{.*}} i32 0, i32 3
+; %va_arg_overflow_size:
+; CHECK: getelementptr {{.*}} i32 0, i32 4
+; %param_origin:
+; CHECK: getelementptr {{.*}} i32 0, i32 5
+; %retval_origin:
+; CHECK: getelementptr {{.*}} i32 0, i32 6
+; CHECK: entry.split:
+
+; Check instrumentation of stores
+
+define void @Store1(i8* nocapture %p, i8 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i8 %x, i8* %p
+ ret void
+}
+
+; CHECK-LABEL: @Store1
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: [[BASE2:%[0-9]+]] = ptrtoint {{.*}} [[PARAM_SHADOW]]
+; CHECK: [[BASE:%[0-9]+]] = ptrtoint {{.*}} [[PARAM_SHADOW]]
+; CHECK: [[SHADOW:%[a-z0-9_]+]] = inttoptr {{.*}} [[BASE]]
+; Load the shadow of %p and check it
+; CHECK: load i64, i64* [[SHADOW]]
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; CHECK: @__msan_metadata_ptr_for_store_1(i8* %p)
+; CHECK: store i8
+; If the new shadow is non-zero, jump to __msan_chain_origin()
+; CHECK: icmp
+; CHECK: br i1
+; CHECK: <label>
+; CHECK: @__msan_chain_origin
+; Storing origin here:
+; CHECK: store i32
+; CHECK: br label
+; CHECK: <label>
+; CHECK: store i8
+; CHECK: ret void
+
+define void @Store2(i16* nocapture %p, i16 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i16 %x, i16* %p
+ ret void
+}
+
+; CHECK-LABEL: @Store2
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; CHECK: [[REG:%[0-9]+]] = bitcast i16* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_store_2(i8* [[REG]])
+; CHECK: store i16
+; If the new shadow is non-zero, jump to __msan_chain_origin()
+; CHECK: icmp
+; CHECK: br i1
+; CHECK: <label>
+; CHECK: @__msan_chain_origin
+; Storing origin here:
+; CHECK: store i32
+; CHECK: br label
+; CHECK: <label>
+; CHECK: store i16
+; CHECK: ret void
+
+
+define void @Store4(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i32 %x, i32* %p
+ ret void
+}
+
+; CHECK-LABEL: @Store4
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i32
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; CHECK: [[REG:%[0-9]+]] = bitcast i32* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_store_4(i8* [[REG]])
+; CHECK: store i32
+; If the new shadow is non-zero, jump to __msan_chain_origin()
+; CHECK: icmp
+; CHECK: br i1
+; CHECK: <label>
+; CHECK: @__msan_chain_origin
+; Storing origin here:
+; CHECK: store i32
+; CHECK: br label
+; CHECK: <label>
+; CHECK: store i32
+; CHECK: ret void
+
+define void @Store8(i64* nocapture %p, i64 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i64 %x, i64* %p
+ ret void
+}
+
+; CHECK-LABEL: @Store8
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; CHECK: [[REG:%[0-9]+]] = bitcast i64* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_store_8(i8* [[REG]])
+; CHECK: store i64
+; If the new shadow is non-zero, jump to __msan_chain_origin()
+; CHECK: icmp
+; CHECK: br i1
+; CHECK: <label>
+; CHECK: @__msan_chain_origin
+; Storing origin here:
+; CHECK: store i32
+; CHECK: br label
+; CHECK: <label>
+; CHECK: store i64
+; CHECK: ret void
+
+define void @Store16(i128* nocapture %p, i128 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i128 %x, i128* %p
+ ret void
+}
+
+; CHECK-LABEL: @Store16
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; CHECK: [[REG:%[0-9]+]] = bitcast i128* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_store_n(i8* [[REG]], i64 16)
+; CHECK: store i128
+; If the new shadow is non-zero, jump to __msan_chain_origin()
+; CHECK: icmp
+; CHECK: br i1
+; CHECK: <label>
+; CHECK: @__msan_chain_origin
+; Storing origin here:
+; CHECK: store i32
+; CHECK: br label
+; CHECK: <label>
+; CHECK: store i128
+; CHECK: ret void
+
+
+; Check instrumentation of loads
+
+define i8 @Load1(i8* nocapture %p) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i8, i8* %p
+ ret i8 %0
+}
+
+; CHECK-LABEL: @Load1
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; Load the value from %p. This is done before accessing the shadow
+; to ease atomic handling.
+; CHECK: load i8
+; CHECK: @__msan_metadata_ptr_for_load_1(i8* %p)
+; Load the shadow and origin.
+; CHECK: load i8
+; CHECK: load i32
+
+
+define i16 @Load2(i16* nocapture %p) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i16, i16* %p
+ ret i16 %0
+}
+
+; CHECK-LABEL: @Load2
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; Load the value from %p. This is done before accessing the shadow
+; to ease atomic handling.
+; CHECK: load i16
+; CHECK: [[REG:%[0-9]+]] = bitcast i16* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_load_2(i8* [[REG]])
+; Load the shadow and origin.
+; CHECK: load i16
+; CHECK: load i32
+
+
+define i32 @Load4(i32* nocapture %p) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i32, i32* %p
+ ret i32 %0
+}
+
+; CHECK-LABEL: @Load4
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; Load the value from %p. This is done before accessing the shadow
+; to ease atomic handling.
+; CHECK: load i32
+; CHECK: [[REG:%[0-9]+]] = bitcast i32* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_load_4(i8* [[REG]])
+; Load the shadow and origin.
+; CHECK: load i32
+; CHECK: load i32
+
+define i64 @Load8(i64* nocapture %p) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i64, i64* %p
+ ret i64 %0
+}
+
+; CHECK-LABEL: @Load8
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; Load the value from %p. This is done before accessing the shadow
+; to ease atomic handling.
+; CHECK: load i64
+; CHECK: [[REG:%[0-9]+]] = bitcast i64* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_load_8(i8* [[REG]])
+; Load the shadow and origin.
+; CHECK: load i64
+; CHECK: load i32
+
+define i128 @Load16(i128* nocapture %p) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i128, i128* %p
+ ret i128 %0
+}
+
+; CHECK-LABEL: @Load16
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK-LABEL: entry.split:
+; CHECK: ptrtoint {{.*}} [[PARAM_SHADOW]]
+; Load the shadow of %p and check it
+; CHECK: load i64
+; CHECK: icmp
+; CHECK: br i1
+; CHECK-LABEL: <label>
+; Load the value from %p. This is done before accessing the shadow
+; to ease atomic handling.
+; CHECK: load i128
+; CHECK: [[REG:%[0-9]+]] = bitcast i128* %p to i8*
+; CHECK: @__msan_metadata_ptr_for_load_n(i8* [[REG]], i64 16)
+; Load the shadow and origin.
+; CHECK: load i128
+; CHECK: load i32
+
+
+; Test kernel-specific va_list instrumentation
+
+%struct.__va_list_tag = type { i32, i32, i8*, i8* }
+declare void @llvm.va_start(i8*) nounwind
+declare void @llvm.va_end(i8*)
+ at .str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+declare dso_local i32 @VAListFn(i8*, %struct.__va_list_tag*) local_unnamed_addr
+
+; Function Attrs: nounwind uwtable
+define dso_local i32 @VarArgFn(i8* %fmt, ...) local_unnamed_addr sanitize_memory #0 {
+entry:
+ %args = alloca [1 x %struct.__va_list_tag], align 16
+ %0 = bitcast [1 x %struct.__va_list_tag]* %args to i8*
+ %arraydecay = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %args, i64 0, i64 0
+ call void @llvm.va_start(i8* nonnull %0)
+ %call = call i32 @VAListFn(i8* %fmt, %struct.__va_list_tag* nonnull %arraydecay)
+ call void @llvm.va_end(i8* nonnull %0)
+ ret i32 %call
+}
+
+; Kernel is built without SSE support.
+attributes #0 = { "target-features"="+fxsr,+x87,-sse" }
+
+; CHECK-LABEL: @VarArgFn
+; CHECK: @__msan_get_context_state()
+; CHECK: [[VA_ARG_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 2
+; CHECK: [[VA_ARG_ORIGIN:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 3
+; CHECK: [[VA_ARG_OVERFLOW_SIZE:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 4
+
+; CHECK-LABEL: entry.split:
+; CHECK: [[OSIZE:%[0-9]+]] = load i64, i64* [[VA_ARG_OVERFLOW_SIZE]]
+; Register save area is 48 bytes for non-SSE builds.
+; CHECK: [[SIZE:%[0-9]+]] = add i64 48, [[OSIZE]]
+; CHECK: [[SHADOWS:%[0-9]+]] = alloca i8, i64 [[SIZE]]
+; CHECK: [[VA_ARG_SHADOW]]
+; CHECK: call void @llvm.memcpy{{.*}}(i8* align 8 [[SHADOWS]], {{.*}}, i64 [[SIZE]]
+; CHECK: [[ORIGINS:%[0-9]+]] = alloca i8, i64 [[SIZE]]
+; CHECK: [[VA_ARG_ORIGIN]]
+; CHECK: call void @llvm.memcpy{{.*}}(i8* align 8 [[ORIGINS]], {{.*}}, i64 [[SIZE]]
+; CHECK: call i32 @VAListFn
+
+; Function Attrs: nounwind uwtable
+define dso_local void @VarArgCaller() local_unnamed_addr sanitize_memory {
+entry:
+ %call = tail call i32 (i8*, ...) @VarArgFn(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 123)
+ ret void
+}
+
+; CHECK-LABEL: @VarArgCaller
+
+; CHECK-LABEL: entry:
+; CHECK: @__msan_get_context_state()
+; CHECK: [[PARAM_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 0
+; CHECK: [[VA_ARG_SHADOW:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 2
+; CHECK: [[VA_ARG_OVERFLOW_SIZE:%[a-z0-9_]+]] = getelementptr {{.*}} i32 0, i32 4
+
+; CHECK-LABEL: entry.split:
+; CHECK: [[PARAM_SI:%[_a-z0-9]+]] = ptrtoint {{.*}} [[PARAM_SHADOW]]
+; CHECK: [[ARG1_S:%[_a-z0-9]+]] = inttoptr i64 [[PARAM_SI]] to i64*
+; First argument is initialized
+; CHECK: store i64 0, i64* [[ARG1_S]]
+
+; Dangling cast of va_arg_shadow[0], unused because the first argument is fixed.
+; CHECK: [[VA_CAST0:%[_a-z0-9]+]] = ptrtoint {{.*}} [[VA_ARG_SHADOW]] to i64
+
+; CHECK: [[VA_CAST1:%[_a-z0-9]+]] = ptrtoint {{.*}} [[VA_ARG_SHADOW]] to i64
+; CHECK: [[ARG1_SI:%[_a-z0-9]+]] = add i64 [[VA_CAST1]], 8
+; CHECK: [[PARG1_S:%[_a-z0-9]+]] = inttoptr i64 [[ARG1_SI]] to i32*
+
+; Shadow for 123 is 0.
+; CHECK: store i32 0, i32* [[ARG1_S]]
+
+; CHECK: store i64 0, i64* [[VA_ARG_OVERFLOW_SIZE]]
+; CHECK: call i32 (i8*, ...) @VarArgFn({{.*}} @.str{{.*}} i32 123)
Modified: llvm/trunk/test/Instrumentation/MemorySanitizer/store-origin.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/MemorySanitizer/store-origin.ll?rev=341637&r1=341636&r2=341637&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/MemorySanitizer/store-origin.ll (original)
+++ llvm/trunk/test/Instrumentation/MemorySanitizer/store-origin.ll Fri Sep 7 02:10:30 2018
@@ -1,5 +1,6 @@
-; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck -check-prefix=CHECK -check-prefix=CHECK-ORIGINS1 %s
-; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=2 -S | FileCheck -check-prefix=CHECK -check-prefix=CHECK-ORIGINS2 %s
+; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck -check-prefixes=CHECK,CHECK-MSAN,CHECK-ORIGINS1 %s
+; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=2 -S | FileCheck -check-prefixes=CHECK,CHECK-MSAN,CHECK-ORIGINS2 %s
+; RUN: opt < %s -msan -msan-kernel=1 -msan-check-access-address=0 -S | FileCheck -check-prefixes=CHECK,CHECK-KMSAN,CHECK-ORIGINS2 %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"
@@ -52,9 +53,17 @@ attributes #1 = { nounwind readnone }
; CHECK-LABEL: @Store
-; CHECK: load {{.*}} @__msan_param_tls
-; CHECK: [[ORIGIN:%[01-9a-z]+]] = load {{.*}} @__msan_param_origin_tls
-; CHECK: store {{.*}}!dbg ![[DBG:[01-9]+]]
+
+; CHECK-MSAN: load {{.*}} @__msan_param_tls
+; CHECK-MSAN: [[ORIGIN:%[0-9a-z]+]] = load {{.*}} @__msan_param_origin_tls
+
+; CHECK-KMSAN-LABEL: entry.split:
+; CHECK-KMSAN: %param_shadow
+; CHECK-KMSAN: load i32, i32*
+; CHECK-KMSAN: %param_origin
+; CHECK-KMSAN: [[ORIGIN:%[0-9a-z]+]] = load i32, i32*
+
+; CHECK: store {{.*}}!dbg ![[DBG:[0-9]+]]
; CHECK: icmp
; CHECK: br i1
; CHECK: <label>
@@ -63,7 +72,7 @@ attributes #1 = { nounwind readnone }
; CHECK-ORIGINS1: store i32 {{.*}}[[ORIGIN]],{{.*}}!dbg !{{.*}}[[DBG]]
; Origin tracking level 2: pass origin value through __msan_chain_origin and store the result.
-; CHECK-ORIGINS2: [[ORIGIN2:%[01-9a-z]+]] = call i32 @__msan_chain_origin(i32 {{.*}}[[ORIGIN]])
+; CHECK-ORIGINS2: [[ORIGIN2:%[0-9a-z]+]] = call i32 @__msan_chain_origin(i32 {{.*}}[[ORIGIN]])
; CHECK-ORIGINS2: store i32 {{.*}}[[ORIGIN2]],{{.*}}!dbg !{{.*}}[[DBG]]
; CHECK: br label{{.*}}!dbg !{{.*}}[[DBG]]
More information about the llvm-commits
mailing list