// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
-// Test that (no_sanitize_memory) functions DO NOT propagate shadow.
+// Test that (no_sanitize_memory) functions propagate shadow.
+
+// Note that at -O0 there is no report, because 'x' in 'f' is spilled to the
+// stack, and then loaded back as a fully initialiazed value (due to
+// no_sanitize_memory attribute).
#include <stdlib.h>
#include <stdio.h>
int x;
int * volatile p = &x;
int y = f(*p);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]
if (y)
exit(0);
return 0;
// The following flags disable parts of MSan instrumentation based on
// blacklist contents and command-line options.
bool InsertChecks;
- bool PropagateShadow;
+ bool LoadShadow;
bool PoisonStack;
bool PoisonUndef;
bool CheckReturnValue;
bool SanitizeFunction = F.getAttributes().hasAttribute(
AttributeSet::FunctionIndex, Attribute::SanitizeMemory);
InsertChecks = SanitizeFunction;
- PropagateShadow = SanitizeFunction;
+ LoadShadow = SanitizeFunction;
PoisonStack = SanitizeFunction && ClPoisonStack;
PoisonUndef = SanitizeFunction && ClPoisonUndef;
// FIXME: Consider using SpecialCaseList to specify a list of functions that
// Finalize PHI nodes.
for (PHINode *PN : ShadowPHINodes) {
- Value *S = getShadow(PN);
- if (isa<Constant>(S)) continue;
PHINode *PNS = cast<PHINode>(getShadow(PN));
PHINode *PNO = MS.TrackOrigins ? cast<PHINode>(getOrigin(PN)) : nullptr;
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));
}
}
/// \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] = PropagateShadow ? SV : getCleanShadow(V);
+ ShadowMap[V] = SV;
}
/// \brief Set Origin to be the origin value for V.
/// 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<Instruction>(V)) {
// For instructions the shadow is already stored in the map.
Value *Shadow = ShadowMap[V];
IRBuilder<> IRB(I.getNextNode());
Type *ShadowTy = getShadowTy(&I);
Value *Addr = I.getPointerOperand();
- if (PropagateShadow) {
+ if (LoadShadow) {
Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
setShadow(&I,
IRB.CreateAlignedLoad(ShadowPtr, I.getAlignment(), "_msld"));
I.setOrdering(addAcquireOrdering(I.getOrdering()));
if (MS.TrackOrigins) {
- if (PropagateShadow) {
+ if (LoadShadow) {
unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
setOrigin(&I,
IRB.CreateAlignedLoad(getOriginPtr(Addr, IRB), Alignment));
Value *Addr = I.getArgOperand(0);
Type *ShadowTy = getShadowTy(&I);
- if (PropagateShadow) {
+ if (LoadShadow) {
Value *ShadowPtr = getShadowPtr(Addr, ShadowTy, IRB);
// We don't know the pointer alignment (could be unaligned SSE load!).
// Have to assume to worst case.
insertShadowCheck(Addr, &I);
if (MS.TrackOrigins) {
- if (PropagateShadow)
+ if (LoadShadow)
setOrigin(&I, IRB.CreateLoad(getOriginPtr(Addr, IRB)));
else
setOrigin(&I, getCleanOrigin());