Subzero: Implemented codegen for poisoning and unpoisoning stack redzones
BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com, stichnot@chromium.org
Review URL: https://codereview.chromium.org/2194853003 .
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp
index 1aa1730..6286299 100644
--- a/src/IceASanInstrumentation.cpp
+++ b/src/IceASanInstrumentation.cpp
@@ -31,12 +31,16 @@
namespace {
-constexpr const char *ASanPrefix = "__asan";
+constexpr SizeT BytesPerWord = sizeof(uint32_t);
constexpr SizeT RzSize = 32;
+constexpr SizeT ShadowScaleLog2 = 3;
+constexpr SizeT ShadowScale = 1 << ShadowScaleLog2;
+constexpr SizeT ShadowLength32 = 1 << (32 - ShadowScaleLog2);
+constexpr int32_t StackPoisonVal = -1;
+constexpr const char *ASanPrefix = "__asan";
constexpr const char *RzPrefix = "__$rz";
constexpr const char *RzArrayName = "__$rz_array";
constexpr const char *RzSizesName = "__$rz_sizes";
-constexpr char RzStackPoison = -1;
const llvm::NaClBitcodeRecord::RecordVector RzContents =
llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R');
@@ -64,7 +68,7 @@
} // end of anonymous namespace
ICE_TLS_DEFINE_FIELD(VarSizeMap *, ASanInstrumentation, LocalVars);
-ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation,
+ICE_TLS_DEFINE_FIELD(std::vector<InstStore *> *, ASanInstrumentation,
LocalDtors);
bool ASanInstrumentation::isInstrumentable(Cfg *Func) {
@@ -162,25 +166,59 @@
// redzone if it is found
void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) {
if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) {
- ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>());
+ ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstStore *>());
ICE_TLS_SET_FIELD(LocalVars, new VarSizeMap());
}
Cfg *Func = Context.getNode()->getCfg();
- bool HasLocals = false;
- LoweringContext C;
- C.init(Context.getNode());
- std::vector<Inst *> Initializations;
- Constant *InitFunc =
- Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_poison"));
- Constant *DestroyFunc =
- Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_unpoison"));
-
+ using Entry = std::pair<SizeT, int32_t>;
+ std::vector<InstAlloca *> NewAllocas;
+ std::vector<Entry> PoisonVals;
+ Variable *FirstShadowLocVar;
+ InstArithmetic *ShadowIndexCalc;
+ InstArithmetic *ShadowLocCalc;
InstAlloca *Cur;
ConstantInteger32 *VarSizeOp;
- while (
- (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) &&
- (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) {
- HasLocals = true;
+ while (!Context.atEnd()) {
+ Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(Context.getCur()));
+ VarSizeOp = (Cur == nullptr)
+ ? nullptr
+ : llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes());
+ if (Cur == nullptr || VarSizeOp == nullptr) {
+ Context.advanceCur();
+ Context.advanceNext();
+ continue;
+ }
+
+ Cur->setDeleted();
+
+ if (PoisonVals.empty()) {
+ // insert leftmost redzone
+ auto *LastRzVar = Func->makeVariable(IceType_i32);
+ LastRzVar->setName(Func, nextRzName());
+ auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, RzSize);
+ constexpr SizeT Alignment = 8;
+ NewAllocas.emplace_back(
+ InstAlloca::create(Func, LastRzVar, ByteCount, Alignment));
+ PoisonVals.emplace_back(Entry{RzSize >> ShadowScaleLog2, StackPoisonVal});
+
+ // Calculate starting address for poisoning
+ FirstShadowLocVar = Func->makeVariable(IceType_i32);
+ FirstShadowLocVar->setName(Func, "firstShadowLoc");
+ auto *ShadowIndexVar = Func->makeVariable(IceType_i32);
+ ShadowIndexVar->setName(Func, "shadowIndex");
+
+ auto *ShadowScaleLog2Const =
+ ConstantInteger32::create(Ctx, IceType_i32, ShadowScaleLog2);
+ auto *ShadowMemLocConst =
+ ConstantInteger32::create(Ctx, IceType_i32, ShadowLength32);
+
+ ShadowIndexCalc =
+ InstArithmetic::create(Func, InstArithmetic::Lshr, ShadowIndexVar,
+ LastRzVar, ShadowScaleLog2Const);
+ ShadowLocCalc =
+ InstArithmetic::create(Func, InstArithmetic::Add, FirstShadowLocVar,
+ ShadowIndexVar, ShadowMemLocConst);
+ }
// create the new alloca that includes a redzone
SizeT VarSize = VarSizeOp->getValue();
@@ -190,72 +228,63 @@
auto *ByteCount =
ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding);
constexpr SizeT Alignment = 8;
- auto *NewVar = InstAlloca::create(Func, Dest, ByteCount, Alignment);
+ NewAllocas.emplace_back(
+ InstAlloca::create(Func, Dest, ByteCount, Alignment));
- // calculate the redzone offset
- Variable *RzLocVar = Func->makeVariable(IceType_i32);
- RzLocVar->setName(Func, nextRzName());
- auto *Offset = ConstantInteger32::create(Ctx, IceType_i32, VarSize);
- auto *RzLoc = InstArithmetic::create(Func, InstArithmetic::Add, RzLocVar,
- Dest, Offset);
-
- // instructions to poison and unpoison the redzone
- constexpr SizeT NumArgs = 2;
- constexpr Variable *Void = nullptr;
- constexpr bool NoTailcall = false;
- auto *RzSizeConst = ConstantInteger32::create(Ctx, IceType_i32, RzPadding);
- auto *RzPoisonConst =
- ConstantInteger32::create(Ctx, IceType_i32, RzStackPoison);
- auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall);
- Init->addArg(RzLocVar);
- Init->addArg(RzSizeConst);
- Init->addArg(RzPoisonConst);
- auto *Destroy =
- InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall);
- Destroy->addArg(RzLocVar);
- Destroy->addArg(RzSizeConst);
- Cur->setDeleted();
- C.insert(NewVar);
- ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy);
- Initializations.emplace_back(RzLoc);
- Initializations.emplace_back(Init);
-
- C.advanceCur();
- C.advanceNext();
+ const SizeT Zeros = VarSize >> ShadowScaleLog2;
+ const SizeT Offset = VarSize % ShadowScale;
+ const SizeT PoisonBytes =
+ ((VarSize + RzPadding) >> ShadowScaleLog2) - Zeros - 1;
+ if (Zeros > 0)
+ PoisonVals.emplace_back(Entry{Zeros, 0});
+ PoisonVals.emplace_back(Entry{1, (Offset == 0) ? StackPoisonVal : Offset});
+ PoisonVals.emplace_back(Entry{PoisonBytes, StackPoisonVal});
+ Context.advanceCur();
+ Context.advanceNext();
}
- C.setInsertPoint(C.getCur());
-
- // add the leftmost redzone
- if (HasLocals) {
- Variable *LastRz = Func->makeVariable(IceType_i32);
- LastRz->setName(Func, nextRzName());
- auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, RzSize);
- constexpr SizeT Alignment = 8;
- auto *RzAlloca = InstAlloca::create(Func, LastRz, ByteCount, Alignment);
-
- constexpr SizeT NumArgs = 2;
- constexpr Variable *Void = nullptr;
- constexpr bool NoTailcall = false;
- auto *RzPoisonConst =
- ConstantInteger32::create(Ctx, IceType_i32, RzStackPoison);
- auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall);
- Init->addArg(LastRz);
- Init->addArg(RzAlloca->getSizeInBytes());
- Init->addArg(RzPoisonConst);
- auto *Destroy =
- InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall);
- Destroy->addArg(LastRz);
- Destroy->addArg(RzAlloca->getSizeInBytes());
- ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy);
- C.insert(RzAlloca);
- C.insert(Init);
+ Context.rewind();
+ if (PoisonVals.empty()) {
+ Context.advanceNext();
+ return;
}
-
- // insert initializers for the redzones
- for (Inst *Init : Initializations) {
- C.insert(Init);
+ for (InstAlloca *RzAlloca : NewAllocas) {
+ Context.insert(RzAlloca);
}
+ Context.insert(ShadowIndexCalc);
+ Context.insert(ShadowLocCalc);
+
+ // Poison redzones
+ std::vector<Entry>::iterator Iter = PoisonVals.begin();
+ for (SizeT Offset = 0; Iter != PoisonVals.end(); Offset += BytesPerWord) {
+ int32_t CurVals[BytesPerWord] = {0};
+ for (uint32_t i = 0; i < BytesPerWord; ++i) {
+ if (Iter == PoisonVals.end())
+ break;
+ Entry Val = *Iter;
+ CurVals[i] = Val.second;
+ --Val.first;
+ if (Val.first > 0)
+ *Iter = Val;
+ else
+ ++Iter;
+ }
+ int32_t Poison = ((CurVals[3] & 0xff) << 24) | ((CurVals[2] & 0xff) << 16) |
+ ((CurVals[1] & 0xff) << 8) | (CurVals[0] & 0xff);
+ if (Poison == 0)
+ continue;
+ auto *PoisonConst = ConstantInteger32::create(Ctx, IceType_i32, Poison);
+ auto *ZeroConst = ConstantInteger32::create(Ctx, IceType_i32, 0);
+ auto *OffsetConst = ConstantInteger32::create(Ctx, IceType_i32, Offset);
+ auto *PoisonAddrVar = Func->makeVariable(IceType_i32);
+ Context.insert(InstArithmetic::create(Func, InstArithmetic::Add,
+ PoisonAddrVar, FirstShadowLocVar,
+ OffsetConst));
+ Context.insert(InstStore::create(Func, PoisonConst, PoisonAddrVar));
+ ICE_TLS_GET_FIELD(LocalDtors)
+ ->emplace_back(InstStore::create(Func, ZeroConst, PoisonAddrVar));
+ }
+ Context.advanceNext();
}
void ASanInstrumentation::instrumentCall(LoweringContext &Context,
@@ -332,22 +361,13 @@
void ASanInstrumentation::instrumentRet(LoweringContext &Context, InstRet *) {
Cfg *Func = Context.getNode()->getCfg();
- InstList::iterator Next = Context.getNext();
Context.setInsertPoint(Context.getCur());
- for (InstCall *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) {
- SizeT NumArgs = RzUnpoison->getNumArgs();
- Variable *Dest = RzUnpoison->getDest();
- Operand *CallTarget = RzUnpoison->getCallTarget();
- bool HasTailCall = RzUnpoison->isTailcall();
- bool IsTargetHelperCall = RzUnpoison->isTargetHelperCall();
- auto *RzUnpoisonCpy = InstCall::create(Func, NumArgs, Dest, CallTarget,
- HasTailCall, IsTargetHelperCall);
- for (int I = 0, Args = RzUnpoison->getNumArgs(); I < Args; ++I) {
- RzUnpoisonCpy->addArg(RzUnpoison->getArg(I));
- }
- Context.insert(RzUnpoisonCpy);
+ for (InstStore *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) {
+ Context.insert(
+ InstStore::create(Func, RzUnpoison->getData(), RzUnpoison->getAddr()));
}
- Context.setNext(Next);
+ Context.advanceCur();
+ Context.advanceNext();
}
void ASanInstrumentation::instrumentStart(Cfg *Func) {
diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h
index f3090ef..3959b36 100644
--- a/src/IceASanInstrumentation.h
+++ b/src/IceASanInstrumentation.h
@@ -54,7 +54,7 @@
void instrumentStart(Cfg *Func) override;
void finishFunc(Cfg *Func) override;
ICE_TLS_DECLARE_FIELD(VarSizeMap *, LocalVars);
- ICE_TLS_DECLARE_FIELD(std::vector<InstCall *> *, LocalDtors);
+ ICE_TLS_DECLARE_FIELD(std::vector<InstStore *> *, LocalDtors);
GlobalSizeMap GlobalSizes;
std::atomic<uint32_t> RzNum;
bool DidProcessGlobals = false;
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index d55f79b..eace318 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -897,7 +897,7 @@
uint32_t Align1 = A1->getAlignInBytes();
uint32_t Align2 = A2->getAlignInBytes();
if (Align1 == Align2)
- return A1->getNumber() > A2->getNumber();
+ return A1->getNumber() < A2->getNumber();
else
return Align1 > Align2;
});
diff --git a/tests_lit/asan_tests/alignment.ll b/tests_lit/asan_tests/alignment.ll
index b288df4..908f2d0 100644
--- a/tests_lit/asan_tests/alignment.ll
+++ b/tests_lit/asan_tests/alignment.ll
@@ -13,34 +13,19 @@
}
; CHECK: func
-; CHECK-NEXT: sub esp,0xbc
-; CHECK-NEXT: lea eax,[esp+0x10]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x20
-; CHECK-NEXT: mov DWORD PTR [esp+0x8],0xffffffff
-; CHECK-NEXT: __asan_poison
-; CHECK-NEXT: lea eax,[esp+0x74]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x3c
-; CHECK-NEXT: mov DWORD PTR [esp+0x8],0xffffffff
-; CHECK-NEXT: __asan_poison
-; CHECK-NEXT: lea eax,[esp+0x35]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x3b
-; CHECK-NEXT: mov DWORD PTR [esp+0x8],0xffffffff
-; CHECK-NEXT: __asan_poison
-; CHECK-NEXT: lea eax,[esp+0x74]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x3c
-; CHECK-NEXT: __asan_unpoison
-; CHECK-NEXT: lea eax,[esp+0x35]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x3b
-; CHECK-NEXT: __asan_unpoison
-; CHECK-NEXT: lea eax,[esp+0x10]
-; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: mov DWORD PTR [esp+0x4],0x20
-; CHECK-NEXT: __asan_unpoison
+; CHECK-NEXT: sub esp,0xa0
+; CHECK-NEXT: lea eax,[esp]
+; CHECK-NEXT: shr eax,0x3
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000000],0xffffffff
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000004],0xffffff04
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000008],0xffffffff
+; CHECK-NEXT: mov DWORD PTR [eax+0x2000000c],0xffffff05
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000010],0xffffffff
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000000],0x0
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000004],0x0
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000008],0x0
+; CHECK-NEXT: mov DWORD PTR [eax+0x2000000c],0x0
+; CHECK-NEXT: mov DWORD PTR [eax+0x20000010],0x0
; CHECK-NEXT: mov eax,0x2a
-; CHECK-NEXT: add esp,0xbc
+; CHECK-NEXT: add esp,0xa0
; CHECK-NEXT: ret
diff --git a/tests_lit/asan_tests/blacklist.ll b/tests_lit/asan_tests/blacklist.ll
index c988a2c..1281721 100644
--- a/tests_lit/asan_tests/blacklist.ll
+++ b/tests_lit/asan_tests/blacklist.ll
@@ -36,14 +36,20 @@
; DUMP-LABEL: ================ Instrumented CFG ================
; DUMP-NEXT: define internal void @func() {
; DUMP-NEXT: __0:
+; DUMP-NEXT: %__$rz0 = alloca i8, i32 32, align 8
; DUMP-NEXT: %local = alloca i8, i32 64, align 8
-; DUMP-NEXT: %__$rz1 = alloca i8, i32 32, align 8
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz1, i32 32, i32 -1)
-; DUMP-NEXT: %__$rz0 = add i32 %local, 4
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz0, i32 60, i32 -1)
+; DUMP-NEXT: %shadowIndex = lshr i32 %__$rz0, 3
+; DUMP-NEXT: %firstShadowLoc = add i32 %shadowIndex, 536870912
+; DUMP-NEXT: %__5 = add i32 %firstShadowLoc, 0
+; DUMP-NEXT: store i32 -1, i32* %__5, align 1
+; DUMP-NEXT: %__6 = add i32 %firstShadowLoc, 4
+; DUMP-NEXT: store i32 -252, i32* %__6, align 1
+; DUMP-NEXT: %__7 = add i32 %firstShadowLoc, 8
+; DUMP-NEXT: store i32 -1, i32* %__7, align 1
; DUMP-NEXT: %heapvar = call i32 @__asan_malloc(i32 42)
; DUMP-NEXT: call void @__asan_free(i32 %heapvar)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz0, i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz1, i32 32)
+; DUMP-NEXT: store i32 0, i32* %__5, align 1
+; DUMP-NEXT: store i32 0, i32* %__6, align 1
+; DUMP-NEXT: store i32 0, i32* %__7, align 1
; DUMP-NEXT: ret void
; DUMP-NEXT: }
diff --git a/tests_lit/asan_tests/errors.ll b/tests_lit/asan_tests/errors.ll
index 3e7f2da..cc403cc 100644
--- a/tests_lit/asan_tests/errors.ll
+++ b/tests_lit/asan_tests/errors.ll
@@ -6,70 +6,115 @@
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
; check with a many off the end local load
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
; check with a one before the front local load
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2\
+; RUN: %t.pexe -o %t && %t 1 2 2>&1 | FileCheck --check-prefix=LOCAL-LOAD %s
; check with a one off the end global load
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-LOAD %s
; check with a many off the end global load
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-LOAD %s
; check with a one before the front global load
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-LOAD %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-LOAD %s
; check with a one off the end local store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 2>&1 | FileCheck \
; RUN: --check-prefix=LOCAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 2>&1 | FileCheck \
+; RUN: --check-prefix=LOCAL-STORE %s
; check with a many off the end local store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 2>&1 | FileCheck \
; RUN: --check-prefix=LOCAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 2>&1 | FileCheck \
+; RUN: --check-prefix=LOCAL-STORE %s
; check with a one before the front local store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 2>&1 | FileCheck \
; RUN: --check-prefix=LOCAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 2>&1 | FileCheck \
+; RUN: --check-prefix=LOCAL-STORE %s
; check with a one off the end global store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-STORE %s
; check with a many off the end global store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 10 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 10 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-STORE %s
; check with a one before the front global store
; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols \
; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 10 11 2>&1 | FileCheck \
; RUN: --check-prefix=GLOBAL-STORE %s
+; RUN: llvm-as %s -o - | pnacl-freeze > %t.pexe && %S/../../pydir/szbuild.py \
+; RUN: --fsanitize-address --sz=-allow-externally-defined-symbols -O2 \
+; RUN: %t.pexe -o %t && %t 1 2 3 4 5 6 7 8 9 10 11 2>&1 | FileCheck \
+; RUN: --check-prefix=GLOBAL-STORE %s
declare external void @exit(i32)
diff --git a/tests_lit/asan_tests/instrumentlocals.ll b/tests_lit/asan_tests/instrumentlocals.ll
index 2cdbe17..38688fe 100644
--- a/tests_lit/asan_tests/instrumentlocals.ll
+++ b/tests_lit/asan_tests/instrumentlocals.ll
@@ -3,7 +3,7 @@
; REQUIRES: allow_dump
; RUN: %p2i -i %s --args -verbose=inst -threads=0 -fsanitize-address \
-; RUN: | FileCheck --check-prefix=DUMP %s
+; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=DUMP %s
; Function with local variables to be instrumented
define internal void @func() {
@@ -12,34 +12,63 @@
%local3 = alloca i8, i32 13, align 2
%local4 = alloca i8, i32 75, align 4
%local5 = alloca i8, i32 64, align 8
+ %i1 = ptrtoint i8* %local1 to i32
+ %i2 = ptrtoint i8* %local2 to i32
+ %i3 = ptrtoint i8* %local3 to i32
+ %i4 = ptrtoint i8* %local4 to i32
+ %i5 = ptrtoint i8* %local5 to i32
+ call void @foo(i32 %i1)
+ call void @foo(i32 %i2)
+ call void @foo(i32 %i3)
+ call void @foo(i32 %i4)
+ call void @foo(i32 %i5)
ret void
}
+declare external void @foo(i32)
+
; DUMP-LABEL: ================ Instrumented CFG ================
; DUMP-NEXT: define internal void @func() {
; DUMP-NEXT: __0:
-; DUMP-NEXT: %local1 = alloca i8, i32 64, align 8
-; DUMP-NEXT: %local2 = alloca i8, i32 64, align 8
-; DUMP-NEXT: %local3 = alloca i8, i32 64, align 8
-; DUMP-NEXT: %local4 = alloca i8, i32 128, align 8
-; DUMP-NEXT: %local5 = alloca i8, i32 96, align 8
-; DUMP-NEXT: %__$rz[[RZ0:[0-9]+]] = alloca i8, i32 32, align 8
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ0]], i32 32, i32 -1)
-; DUMP-NEXT: %__$rz[[RZ1:[0-9]+]] = add i32 %local1, 4
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ1]], i32 60, i32 -1)
-; DUMP-NEXT: %__$rz[[RZ2:[0-9]+]] = add i32 %local2, 32
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ2]], i32 32, i32 -1)
-; DUMP-NEXT: %__$rz[[RZ3:[0-9]+]] = add i32 %local3, 13
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ3]], i32 51, i32 -1)
-; DUMP-NEXT: %__$rz[[RZ4:[0-9]+]] = add i32 %local4, 75
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ4]], i32 53, i32 -1)
-; DUMP-NEXT: %__$rz[[RZ5:[0-9]+]] = add i32 %local5, 64
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz[[RZ5]], i32 32, i32 -1)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ1]], i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ2]], i32 32)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ3]], i32 51)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ4]], i32 53)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ5]], i32 32)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz[[RZ0]], i32 32)
-; DUMP-NEXT: ret void
+; DUMP-NEXT: %__$rz0 = alloca i8, i32 32, align 8
+; DUMP-NEXT: %local1 = alloca i8, i32 64, align 8
+; DUMP-NEXT: %local2 = alloca i8, i32 64, align 8
+; DUMP-NEXT: %local3 = alloca i8, i32 64, align 8
+; DUMP-NEXT: %local4 = alloca i8, i32 128, align 8
+; DUMP-NEXT: %local5 = alloca i8, i32 96, align 8
+; DUMP-NEXT: %shadowIndex = lshr i32 %__$rz0, 3
+; DUMP-NEXT: %firstShadowLoc = add i32 %shadowIndex, 536870912
+; DUMP-NEXT: %__8 = add i32 %firstShadowLoc, 0
+; DUMP-NEXT: store i32 -1, i32* %__8, align 1
+; DUMP-NEXT: %__9 = add i32 %firstShadowLoc, 4
+; DUMP-NEXT: store i32 -252, i32* %__9, align 1
+; DUMP-NEXT: %__10 = add i32 %firstShadowLoc, 8
+; DUMP-NEXT: store i32 -1, i32* %__10, align 1
+; DUMP-NEXT: %__11 = add i32 %firstShadowLoc, 16
+; DUMP-NEXT: store i32 -1, i32* %__11, align 1
+; DUMP-NEXT: %__12 = add i32 %firstShadowLoc, 20
+; DUMP-NEXT: store i32 -64256, i32* %__12, align 1
+; DUMP-NEXT: %__13 = add i32 %firstShadowLoc, 24
+; DUMP-NEXT: store i32 -1, i32* %__13, align 1
+; DUMP-NEXT: %__14 = add i32 %firstShadowLoc, 36
+; DUMP-NEXT: store i32 -64768, i32* %__14, align 1
+; DUMP-NEXT: %__15 = add i32 %firstShadowLoc, 40
+; DUMP-NEXT: store i32 -1, i32* %__15, align 1
+; DUMP-NEXT: %__16 = add i32 %firstShadowLoc, 52
+; DUMP-NEXT: store i32 -1, i32* %__16, align 1
+; DUMP-NEXT: call void @foo(i32 %local1)
+; DUMP-NEXT: call void @foo(i32 %local2)
+; DUMP-NEXT: call void @foo(i32 %local3)
+; DUMP-NEXT: call void @foo(i32 %local4)
+; DUMP-NEXT: call void @foo(i32 %local5)
+; DUMP-NEXT: store i32 0, i32* %__8, align 1
+; DUMP-NEXT: store i32 0, i32* %__9, align 1
+; DUMP-NEXT: store i32 0, i32* %__10, align 1
+; DUMP-NEXT: store i32 0, i32* %__11, align 1
+; DUMP-NEXT: store i32 0, i32* %__12, align 1
+; DUMP-NEXT: store i32 0, i32* %__13, align 1
+; DUMP-NEXT: store i32 0, i32* %__14, align 1
+; DUMP-NEXT: store i32 0, i32* %__15, align 1
+; DUMP-NEXT: store i32 0, i32* %__16, align 1
+; DUMP-NEXT: ret void
; DUMP-NEXT: }
diff --git a/tests_lit/asan_tests/multiple_returns.ll b/tests_lit/asan_tests/multiple_returns.ll
index a49e26f..ec5ed6a 100644
--- a/tests_lit/asan_tests/multiple_returns.ll
+++ b/tests_lit/asan_tests/multiple_returns.ll
@@ -16,27 +16,38 @@
ret void
}
-; DUMP-LABEL: ================ Instrumented CFG ================
+; DUMP-LABEL:================ Instrumented CFG ================
; DUMP-NEXT: define internal void @ret_twice(i32 %condarg) {
; DUMP-NEXT: __0:
+; DUMP-NEXT: %__$rz0 = alloca i8, i32 32, align 8
; DUMP-NEXT: %local1 = alloca i8, i32 64, align 8
; DUMP-NEXT: %local2 = alloca i8, i32 64, align 8
-; DUMP-NEXT: %__$rz2 = alloca i8, i32 32, align 8
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz2, i32 32, i32 -1)
-; DUMP-NEXT: %__$rz0 = add i32 %local1, 4
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz0, i32 60, i32 -1)
-; DUMP-NEXT: %__$rz1 = add i32 %local2, 4
-; DUMP-NEXT: call void @__asan_poison(i32 %__$rz1, i32 60, i32 -1)
+; DUMP-NEXT: %shadowIndex = lshr i32 %__$rz0, 3
+; DUMP-NEXT: %firstShadowLoc = add i32 %shadowIndex, 53687091
+; DUMP-NEXT: %__7 = add i32 %firstShadowLoc, 0
+; DUMP-NEXT: store i32 -1, i32* %__7, align 1
+; DUMP-NEXT: %__8 = add i32 %firstShadowLoc, 4
+; DUMP-NEXT: store i32 -252, i32* %__8, align 1
+; DUMP-NEXT: %__9 = add i32 %firstShadowLoc, 8
+; DUMP-NEXT: store i32 -1, i32* %__9, align 1
+; DUMP-NEXT: %__10 = add i32 %firstShadowLoc, 12
+; DUMP-NEXT: store i32 -252, i32* %__10, align 1
+; DUMP-NEXT: %__11 = add i32 %firstShadowLoc, 16
+; DUMP-NEXT: store i32 -1, i32* %__11, align 1
; DUMP-NEXT: %cond = icmp ne i32 %condarg, 0
; DUMP-NEXT: br i1 %cond, label %yes, label %no
; DUMP-NEXT: yes:
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz0, i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz1, i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz2, i32 32)
+; DUMP-NEXT: store i32 0, i32* %__7, align 1
+; DUMP-NEXT: store i32 0, i32* %__8, align 1
+; DUMP-NEXT: store i32 0, i32* %__9, align 1
+; DUMP-NEXT: store i32 0, i32* %__10, align 1
+; DUMP-NEXT: store i32 0, i32* %__11, align 1
; DUMP-NEXT: ret void
; DUMP-NEXT: no:
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz0, i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz1, i32 60)
-; DUMP-NEXT: call void @__asan_unpoison(i32 %__$rz2, i32 32)
+; DUMP-NEXT: store i32 0, i32* %__7, align 1
+; DUMP-NEXT: store i32 0, i32* %__8, align 1
+; DUMP-NEXT: store i32 0, i32* %__9, align 1
+; DUMP-NEXT: store i32 0, i32* %__10, align 1
+; DUMP-NEXT: store i32 0, i32* %__11, align 1
; DUMP-NEXT: ret void
-; DUMP-NEXT: }
\ No newline at end of file
+; DUMP-NEXT: }
diff --git a/tests_lit/asan_tests/scatteredallocas.ll b/tests_lit/asan_tests/scatteredallocas.ll
new file mode 100644
index 0000000..5c4588c
--- /dev/null
+++ b/tests_lit/asan_tests/scatteredallocas.ll
@@ -0,0 +1,63 @@
+; Test that static allocas throughout the entry block are instrumented correctly
+
+; REQUIRES: allow_dump
+
+; RUN: %p2i -i %s --args -verbose=inst -threads=0 -fsanitize-address \
+; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=DUMP %s
+
+declare external i32 @malloc(i32)
+declare external void @free(i32)
+
+define void @func() {
+ %a = alloca i8, i32 4, align 4
+ %m1 = call i32 @malloc(i32 42)
+ %b = alloca i8, i32 16, align 4
+ store i8 50, i8* %a, align 1
+ %c = alloca i8, i32 8, align 8
+ call void @free(i32 %m1)
+ %d = alloca i8, i32 12, align 4
+ ret void
+}
+
+; DUMP-LABEL: ================ Instrumented CFG ================
+; DUMP-NEXT: define void @func() {
+; DUMP-NEXT: __0:
+; DUMP-NEXT: %__$rz0 = alloca i8, i32 32, align 8
+; DUMP-NEXT: %a = alloca i8, i32 64, align 8
+; DUMP-NEXT: %b = alloca i8, i32 64, align 8
+; DUMP-NEXT: %c = alloca i8, i32 64, align 8
+; DUMP-NEXT: %d = alloca i8, i32 64, align 8
+; DUMP-NEXT: %shadowIndex = lshr i32 %__$rz0, 3
+; DUMP-NEXT: %firstShadowLoc = add i32 %shadowIndex, 536870912
+; DUMP-NEXT: %__8 = add i32 %firstShadowLoc, 0
+; DUMP-NEXT: store i32 -1, i32* %__8, align 1
+; DUMP-NEXT: %__9 = add i32 %firstShadowLoc, 4
+; DUMP-NEXT: store i32 -252, i32* %__9, align 1
+; DUMP-NEXT: %__10 = add i32 %firstShadowLoc, 8
+; DUMP-NEXT: store i32 -1, i32* %__10, align 1
+; DUMP-NEXT: %__11 = add i32 %firstShadowLoc, 12
+; DUMP-NEXT: store i32 -65536, i32* %__11, align 1
+; DUMP-NEXT: %__12 = add i32 %firstShadowLoc, 16
+; DUMP-NEXT: store i32 -1, i32* %__12, align 1
+; DUMP-NEXT: %__13 = add i32 %firstShadowLoc, 20
+; DUMP-NEXT: store i32 -256, i32* %__13, align 1
+; DUMP-NEXT: %__14 = add i32 %firstShadowLoc, 24
+; DUMP-NEXT: store i32 -1, i32* %__14, align 1
+; DUMP-NEXT: %__15 = add i32 %firstShadowLoc, 28
+; DUMP-NEXT: store i32 -64512, i32* %__15, align 1
+; DUMP-NEXT: %__16 = add i32 %firstShadowLoc, 32
+; DUMP-NEXT: store i32 -1, i32* %__16, align 1
+; DUMP-NEXT: %m1 = call i32 @__asan_malloc(i32 42)
+; DUMP-NEXT: store i8 50, i8* %a, align 1
+; DUMP-NEXT: call void @__asan_free(i32 %m1)
+; DUMP-NEXT: store i32 0, i32* %__8, align 1
+; DUMP-NEXT: store i32 0, i32* %__9, align 1
+; DUMP-NEXT: store i32 0, i32* %__10, align 1
+; DUMP-NEXT: store i32 0, i32* %__11, align 1
+; DUMP-NEXT: store i32 0, i32* %__12, align 1
+; DUMP-NEXT: store i32 0, i32* %__13, align 1
+; DUMP-NEXT: store i32 0, i32* %__14, align 1
+; DUMP-NEXT: store i32 0, i32* %__15, align 1
+; DUMP-NEXT: store i32 0, i32* %__16, align 1
+; DUMP-NEXT: ret void
+; DUMP-NEXT: }
\ No newline at end of file
diff --git a/tests_lit/llvm2ice_tests/fused-alloca-arg.ll b/tests_lit/llvm2ice_tests/fused-alloca-arg.ll
index d76755e..1b009ba 100644
--- a/tests_lit/llvm2ice_tests/fused-alloca-arg.ll
+++ b/tests_lit/llvm2ice_tests/fused-alloca-arg.ll
@@ -49,16 +49,16 @@
; CHECK-LABEL: caller2
; CHECK-NEXT: sub esp,0x6c
; CHECK-NEXT: mov eax,DWORD PTR [esp+0x70]
-; CHECK-NEXT: mov DWORD PTR [esp+0x40],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x20],eax
+; CHECK-NEXT: mov DWORD PTR [esp+0x40],eax
; CHECK-NEXT: mov DWORD PTR [esp],eax
-; CHECK-NEXT: lea eax,[esp+0x40]
+; CHECK-NEXT: lea eax,[esp+0x20]
; CHECK-NEXT: mov DWORD PTR [esp+0x4],eax
-; CHECK-NEXT: lea eax,[esp+0x20]
-; CHECK-NEXT: mov DWORD PTR [esp+0x8],eax
; CHECK-NEXT: lea eax,[esp+0x40]
-; CHECK-NEXT: mov DWORD PTR [esp+0xc],eax
+; CHECK-NEXT: mov DWORD PTR [esp+0x8],eax
; CHECK-NEXT: lea eax,[esp+0x20]
+; CHECK-NEXT: mov DWORD PTR [esp+0xc],eax
+; CHECK-NEXT: lea eax,[esp+0x40]
; CHECK-NEXT: mov DWORD PTR [esp+0x10],eax
; CHECK-NEXT: call
; CHECK-NEXT: add esp,0x6c
diff --git a/tests_lit/llvm2ice_tests/fused-alloca.ll b/tests_lit/llvm2ice_tests/fused-alloca.ll
index b7e683f..1b46305 100644
--- a/tests_lit/llvm2ice_tests/fused-alloca.ll
+++ b/tests_lit/llvm2ice_tests/fused-alloca.ll
@@ -21,8 +21,8 @@
; CHECK-LABEL: fused_small_align
; CHECK-NEXT: sub esp,0x30
; CHECK-NEXT: mov eax,DWORD PTR [esp+0x34]
-; CHECK-NEXT: mov DWORD PTR [esp+0x1c],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x10],eax
+; CHECK-NEXT: mov DWORD PTR [esp+0x18],eax
; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: add esp,0x30
@@ -46,9 +46,9 @@
; CHECK-NEXT: sub esp,0x80
; CHECK-NEXT: and esp,0xffffffc0
; CHECK-NEXT: mov eax,DWORD PTR [ebp+0x8]
-; CHECK-NEXT: mov DWORD PTR [esp+0x60],eax
-; CHECK-NEXT: mov DWORD PTR [esp],eax
; CHECK-NEXT: mov DWORD PTR [esp+0x40],eax
+; CHECK-NEXT: mov DWORD PTR [esp],eax
+; CHECK-NEXT: mov DWORD PTR [esp+0x60],eax
; CHECK-NEXT: mov esp,ebp
; CHECK-NEXT: pop ebp
@@ -154,10 +154,10 @@
; CHECK-NEXT: add edx,0x0
; CHECK-NEXT: sub esp,0x10
; CHECK-NEXT: mov ebx,esp
-; CHECK-NEXT: mov DWORD PTR [ecx],eax
; CHECK-NEXT: mov DWORD PTR [edx],eax
-; CHECK-NEXT: mov DWORD PTR [ebp-0x24],eax
+; CHECK-NEXT: mov DWORD PTR [ecx],eax
; CHECK-NEXT: mov DWORD PTR [ebp-0x14],eax
+; CHECK-NEXT: mov DWORD PTR [ebp-0x24],eax
; CHECK-NEXT: mov DWORD PTR [ebx],eax
; CHECK-NEXT: mov esp,ebp
; CHECK-NEXT: pop ebp