mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
[msan] Origin tracking with history.
LLVM part of MSan implementation of advanced origin tracking, when we record not only creation point, but all locations where an uninitialized value was stored to memory, too. llvm-svn: 204151
This commit is contained in:
parent
119221ccbc
commit
4e42dcfe00
@ -71,7 +71,7 @@ ModulePass *createAddressSanitizerModulePass(
|
|||||||
bool CheckInitOrder = true, StringRef BlacklistFile = StringRef());
|
bool CheckInitOrder = true, StringRef BlacklistFile = StringRef());
|
||||||
|
|
||||||
// Insert MemorySanitizer instrumentation (detection of uninitialized reads)
|
// Insert MemorySanitizer instrumentation (detection of uninitialized reads)
|
||||||
FunctionPass *createMemorySanitizerPass(bool TrackOrigins = false,
|
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0,
|
||||||
StringRef BlacklistFile = StringRef());
|
StringRef BlacklistFile = StringRef());
|
||||||
|
|
||||||
// Insert ThreadSanitizer (race detection) instrumentation
|
// Insert ThreadSanitizer (race detection) instrumentation
|
||||||
|
@ -133,9 +133,9 @@ static const unsigned kShadowTLSAlignment = 8;
|
|||||||
///
|
///
|
||||||
/// Adds a section to MemorySanitizer report that points to the allocation
|
/// Adds a section to MemorySanitizer report that points to the allocation
|
||||||
/// (stack or heap) the uninitialized bits came from originally.
|
/// (stack or heap) the uninitialized bits came from originally.
|
||||||
static cl::opt<bool> ClTrackOrigins("msan-track-origins",
|
static cl::opt<int> ClTrackOrigins("msan-track-origins",
|
||||||
cl::desc("Track origins (allocation sites) of poisoned memory"),
|
cl::desc("Track origins (allocation sites) of poisoned memory"),
|
||||||
cl::Hidden, cl::init(false));
|
cl::Hidden, cl::init(0));
|
||||||
static cl::opt<bool> ClKeepGoing("msan-keep-going",
|
static cl::opt<bool> ClKeepGoing("msan-keep-going",
|
||||||
cl::desc("keep going after reporting a UMR"),
|
cl::desc("keep going after reporting a UMR"),
|
||||||
cl::Hidden, cl::init(false));
|
cl::Hidden, cl::init(false));
|
||||||
@ -199,10 +199,10 @@ namespace {
|
|||||||
/// uninitialized reads.
|
/// uninitialized reads.
|
||||||
class MemorySanitizer : public FunctionPass {
|
class MemorySanitizer : public FunctionPass {
|
||||||
public:
|
public:
|
||||||
MemorySanitizer(bool TrackOrigins = false,
|
MemorySanitizer(int TrackOrigins = 0,
|
||||||
StringRef BlacklistFile = StringRef())
|
StringRef BlacklistFile = StringRef())
|
||||||
: FunctionPass(ID),
|
: FunctionPass(ID),
|
||||||
TrackOrigins(TrackOrigins || ClTrackOrigins),
|
TrackOrigins(std::max(TrackOrigins, (int)ClTrackOrigins)),
|
||||||
DL(0),
|
DL(0),
|
||||||
WarningFn(0),
|
WarningFn(0),
|
||||||
BlacklistFile(BlacklistFile.empty() ? ClBlacklistFile : BlacklistFile),
|
BlacklistFile(BlacklistFile.empty() ? ClBlacklistFile : BlacklistFile),
|
||||||
@ -216,7 +216,7 @@ class MemorySanitizer : public FunctionPass {
|
|||||||
void initializeCallbacks(Module &M);
|
void initializeCallbacks(Module &M);
|
||||||
|
|
||||||
/// \brief Track origins (allocation points) of uninitialized values.
|
/// \brief Track origins (allocation points) of uninitialized values.
|
||||||
bool TrackOrigins;
|
int TrackOrigins;
|
||||||
|
|
||||||
const DataLayout *DL;
|
const DataLayout *DL;
|
||||||
LLVMContext *C;
|
LLVMContext *C;
|
||||||
@ -250,6 +250,9 @@ class MemorySanitizer : public FunctionPass {
|
|||||||
Value *MsanSetAllocaOrigin4Fn;
|
Value *MsanSetAllocaOrigin4Fn;
|
||||||
/// \brief Run-time helper that poisons stack on function entry.
|
/// \brief Run-time helper that poisons stack on function entry.
|
||||||
Value *MsanPoisonStackFn;
|
Value *MsanPoisonStackFn;
|
||||||
|
/// \brief Run-time helper that records a store (or any event) of an
|
||||||
|
/// uninitialized value and returns an updated origin id encoding this info.
|
||||||
|
Value *MsanChainOriginFn;
|
||||||
/// \brief MSan runtime replacements for memmove, memcpy and memset.
|
/// \brief MSan runtime replacements for memmove, memcpy and memset.
|
||||||
Value *MemmoveFn, *MemcpyFn, *MemsetFn;
|
Value *MemmoveFn, *MemcpyFn, *MemsetFn;
|
||||||
|
|
||||||
@ -286,7 +289,7 @@ INITIALIZE_PASS(MemorySanitizer, "msan",
|
|||||||
"MemorySanitizer: detects uninitialized reads.",
|
"MemorySanitizer: detects uninitialized reads.",
|
||||||
false, false)
|
false, false)
|
||||||
|
|
||||||
FunctionPass *llvm::createMemorySanitizerPass(bool TrackOrigins,
|
FunctionPass *llvm::createMemorySanitizerPass(int TrackOrigins,
|
||||||
StringRef BlacklistFile) {
|
StringRef BlacklistFile) {
|
||||||
return new MemorySanitizer(TrackOrigins, BlacklistFile);
|
return new MemorySanitizer(TrackOrigins, BlacklistFile);
|
||||||
}
|
}
|
||||||
@ -323,6 +326,8 @@ void MemorySanitizer::initializeCallbacks(Module &M) {
|
|||||||
IRB.getInt8PtrTy(), IntptrTy, NULL);
|
IRB.getInt8PtrTy(), IntptrTy, NULL);
|
||||||
MsanPoisonStackFn = M.getOrInsertFunction(
|
MsanPoisonStackFn = M.getOrInsertFunction(
|
||||||
"__msan_poison_stack", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy, NULL);
|
"__msan_poison_stack", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy, NULL);
|
||||||
|
MsanChainOriginFn = M.getOrInsertFunction(
|
||||||
|
"__msan_chain_origin", IRB.getInt32Ty(), IRB.getInt32Ty(), NULL);
|
||||||
MemmoveFn = M.getOrInsertFunction(
|
MemmoveFn = M.getOrInsertFunction(
|
||||||
"__msan_memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
|
"__msan_memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
|
||||||
IRB.getInt8PtrTy(), IntptrTy, NULL);
|
IRB.getInt8PtrTy(), IntptrTy, NULL);
|
||||||
@ -520,6 +525,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
|||||||
<< F.getName() << "'\n");
|
<< F.getName() << "'\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value *updateOrigin(Value *V, IRBuilder<> &IRB) {
|
||||||
|
if (MS.TrackOrigins <= 1) return V;
|
||||||
|
return IRB.CreateCall(MS.MsanChainOriginFn, V);
|
||||||
|
}
|
||||||
|
|
||||||
void materializeStores() {
|
void materializeStores() {
|
||||||
for (size_t i = 0, n = StoreList.size(); i < n; i++) {
|
for (size_t i = 0, n = StoreList.size(); i < n; i++) {
|
||||||
StoreInst& I = *dyn_cast<StoreInst>(StoreList[i]);
|
StoreInst& I = *dyn_cast<StoreInst>(StoreList[i]);
|
||||||
@ -544,8 +554,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
|||||||
if (MS.TrackOrigins) {
|
if (MS.TrackOrigins) {
|
||||||
unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
|
unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
|
||||||
if (isa<StructType>(Shadow->getType())) {
|
if (isa<StructType>(Shadow->getType())) {
|
||||||
IRB.CreateAlignedStore(getOrigin(Val), getOriginPtr(Addr, IRB),
|
IRB.CreateAlignedStore(updateOrigin(getOrigin(Val), IRB),
|
||||||
Alignment);
|
getOriginPtr(Addr, IRB), Alignment);
|
||||||
} else {
|
} else {
|
||||||
Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB);
|
Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB);
|
||||||
|
|
||||||
@ -560,8 +570,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
|||||||
Instruction *CheckTerm =
|
Instruction *CheckTerm =
|
||||||
SplitBlockAndInsertIfThen(Cmp, &I, false, MS.OriginStoreWeights);
|
SplitBlockAndInsertIfThen(Cmp, &I, false, MS.OriginStoreWeights);
|
||||||
IRBuilder<> IRBNew(CheckTerm);
|
IRBuilder<> IRBNew(CheckTerm);
|
||||||
IRBNew.CreateAlignedStore(getOrigin(Val), getOriginPtr(Addr, IRBNew),
|
IRBNew.CreateAlignedStore(updateOrigin(getOrigin(Val), IRBNew),
|
||||||
Alignment);
|
getOriginPtr(Addr, IRBNew), Alignment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
test/Instrumentation/MemorySanitizer/store-origin.ll
Normal file
34
test/Instrumentation/MemorySanitizer/store-origin.ll
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
; 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
|
||||||
|
|
||||||
|
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 origin instrumentation of stores
|
||||||
|
|
||||||
|
define void @Store(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
|
||||||
|
entry:
|
||||||
|
store i32 %x, i32* %p, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @Store
|
||||||
|
; CHECK: load {{.*}} @__msan_param_tls
|
||||||
|
; CHECK: [[ORIGIN:%[01-9a-z]+]] = load {{.*}} @__msan_param_origin_tls
|
||||||
|
; CHECK: store
|
||||||
|
; CHECK: icmp
|
||||||
|
; CHECK: br i1
|
||||||
|
; CHECK: <label>
|
||||||
|
|
||||||
|
; Origin tracking level 1: simply store the origin value
|
||||||
|
; CHECK-ORIGINS1: store i32 {{.*}}[[ORIGIN]],
|
||||||
|
|
||||||
|
; 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: store i32 {{.*}}[[ORIGIN2]],
|
||||||
|
|
||||||
|
; CHECK: br label
|
||||||
|
; CHECK: <label>
|
||||||
|
; CHECK: store
|
||||||
|
; CHECK: ret void
|
Loading…
Reference in New Issue
Block a user