Instrumented local variables and implemented runtime.
BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com
Review URL: https://codereview.chromium.org/2095763002 .
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp
index f4b47e1..83ebc19 100644
--- a/src/IceASanInstrumentation.cpp
+++ b/src/IceASanInstrumentation.cpp
@@ -24,10 +24,12 @@
#include <sstream>
#include <unordered_map>
+#include <vector>
namespace Ice {
namespace {
+
constexpr SizeT RzSize = 32;
const std::string RzPrefix = "__$rz";
const llvm::NaClBitcodeRecord::RecordVector RzContents =
@@ -42,6 +44,9 @@
} // end of anonymous namespace
+ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation,
+ LocalDtors);
+
// Create redzones around all global variables, ensuring that the initializer
// types of the redzones and their associated globals match so that they are
// laid out together in memory.
@@ -126,38 +131,95 @@
// Check for an alloca signaling the presence of local variables and add a
// redzone if it is found
void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) {
- auto *FirstAlloca = llvm::dyn_cast<InstAlloca>(Context.getCur());
- if (FirstAlloca == nullptr)
- return;
+ if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr)
+ ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>());
- constexpr SizeT Alignment = 4;
- InstAlloca *RzAlloca = createLocalRz(Context, RzSize, Alignment);
-
- // insert before the current instruction
- InstList::iterator Next = Context.getNext();
- Context.setInsertPoint(Context.getCur());
- Context.insert(RzAlloca);
- Context.setNext(Next);
-}
-
-void ASanInstrumentation::instrumentAlloca(LoweringContext &Context,
- InstAlloca *Instr) {
- auto *VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Instr->getSizeInBytes());
- SizeT VarSize = (VarSizeOp == nullptr) ? RzSize : VarSizeOp->getValue();
- SizeT Padding = Utils::OffsetToAlignment(VarSize, RzSize);
- constexpr SizeT Alignment = 1;
- InstAlloca *Rz = createLocalRz(Context, RzSize + Padding, Alignment);
- Context.insert(Rz);
-}
-
-InstAlloca *ASanInstrumentation::createLocalRz(LoweringContext &Context,
- SizeT Size, SizeT Alignment) {
Cfg *Func = Context.getNode()->getCfg();
- Variable *Rz = Func->makeVariable(IceType_i32);
- Rz->setName(Func, nextRzName());
- auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, Size);
- auto *RzAlloca = InstAlloca::create(Func, Rz, ByteCount, Alignment);
- return RzAlloca;
+ 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"));
+
+ InstAlloca *Cur;
+ ConstantInteger32 *VarSizeOp;
+ while (
+ (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) &&
+ (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) {
+ HasLocals = true;
+
+ // create the new alloca that includes a redzone
+ SizeT VarSize = VarSizeOp->getValue();
+ Variable *Dest = Cur->getDest();
+ SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize);
+ auto *ByteCount =
+ ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding);
+ constexpr SizeT Alignment = 8;
+ auto *NewVar = 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 *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall);
+ auto *Destroy =
+ InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall);
+ Init->addArg(RzLocVar);
+ Destroy->addArg(RzLocVar);
+ auto *RzSizeConst = ConstantInteger32::create(Ctx, IceType_i32, RzPadding);
+ Init->addArg(RzSizeConst);
+ 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();
+ }
+
+ 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 *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall);
+ auto *Destroy =
+ InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall);
+ Init->addArg(LastRz);
+ Destroy->addArg(LastRz);
+ Init->addArg(RzAlloca->getSizeInBytes());
+ Destroy->addArg(RzAlloca->getSizeInBytes());
+
+ ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy);
+ C.insert(RzAlloca);
+ C.insert(Init);
+ }
+
+ // insert initializers for the redzones
+ for (Inst *Init : Initializations) {
+ C.insert(Init);
+ }
}
void ASanInstrumentation::instrumentCall(LoweringContext &Context,
@@ -214,6 +276,15 @@
Context.setNext(Next);
}
+void ASanInstrumentation::instrumentRet(LoweringContext &Context, InstRet *) {
+ InstList::iterator Next = Context.getNext();
+ Context.setInsertPoint(Context.getCur());
+ for (InstCall *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) {
+ Context.insert(RzUnpoison);
+ }
+ Context.setNext(Next);
+}
+
void ASanInstrumentation::instrumentStart(Cfg *Func) {
Constant *ShadowMemInit =
Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init"));
@@ -224,4 +295,10 @@
Func->getEntryNode()->getInsts().push_front(Call);
}
+// TODO(tlively): make this more efficient with swap idiom
+void ASanInstrumentation::finishFunc(Cfg *Func) {
+ (void)Func;
+ ICE_TLS_GET_FIELD(LocalDtors)->clear();
+}
+
} // end of namespace Ice
diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h
index 2cf5c59..de250d4 100644
--- a/src/IceASanInstrumentation.h
+++ b/src/IceASanInstrumentation.h
@@ -31,7 +31,9 @@
ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;
public:
- ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {}
+ ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {
+ ICE_TLS_INIT_FIELD(LocalDtors);
+ }
void instrumentGlobals(VariableDeclarationList &Globals) override;
private:
@@ -40,15 +42,15 @@
VariableDeclaration *RzArray,
SizeT &RzArraySize,
VariableDeclaration *Global);
- InstAlloca *createLocalRz(LoweringContext &Context, SizeT Size,
- SizeT Alignment);
void instrumentFuncStart(LoweringContext &Context) override;
- void instrumentAlloca(LoweringContext &Context, InstAlloca *Instr) override;
void instrumentCall(LoweringContext &Context, InstCall *Instr) override;
+ void instrumentRet(LoweringContext &Context, InstRet *Instr) override;
void instrumentLoad(LoweringContext &Context, InstLoad *Instr) override;
void instrumentStore(LoweringContext &Context, InstStore *Instr) override;
void instrumentAccess(LoweringContext &Context, Operand *Op, SizeT Size);
void instrumentStart(Cfg *Func) override;
+ void finishFunc(Cfg *Func) override;
+ ICE_TLS_DECLARE_FIELD(std::vector<InstCall *> *, LocalDtors);
bool DidInsertRedZones = false;
std::atomic<uint32_t> RzNum;
};
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index a113b95..c2b4d06 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -645,16 +645,19 @@
getTarget()->lowerArguments();
}
-void Cfg::sortAndCombineAllocas(CfgVector<Inst *> &Allocas,
+void Cfg::sortAndCombineAllocas(CfgVector<InstAlloca *> &Allocas,
uint32_t CombinedAlignment, InstList &Insts,
AllocaBaseVariableType BaseVariableType) {
if (Allocas.empty())
return;
// Sort by decreasing alignment.
- std::sort(Allocas.begin(), Allocas.end(), [](Inst *I1, Inst *I2) {
- auto *A1 = llvm::dyn_cast<InstAlloca>(I1);
- auto *A2 = llvm::dyn_cast<InstAlloca>(I2);
- return A1->getAlignInBytes() > A2->getAlignInBytes();
+ std::sort(Allocas.begin(), Allocas.end(), [](InstAlloca *A1, InstAlloca *A2) {
+ uint32_t Align1 = A1->getAlignInBytes();
+ uint32_t Align2 = A2->getAlignInBytes();
+ if (Align1 == Align2)
+ return A1->getNumber() > A2->getNumber();
+ else
+ return Align1 > Align2;
});
// Process the allocas in order of decreasing stack alignment. This allows
// us to pack less-aligned pieces after more-aligned ones, resulting in less
@@ -746,6 +749,8 @@
bool HasLargeAlignment = false;
bool HasDynamicAllocation = false;
for (Inst &Instr : EntryNode->getInsts()) {
+ if (Instr.isDeleted())
+ continue;
if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
uint32_t AlignmentParam = Alloca->getAlignInBytes();
if (AlignmentParam > StackAlignment)
@@ -769,6 +774,8 @@
if (Node == EntryNode)
continue;
for (Inst &Instr : Node->getInsts()) {
+ if (Instr.isDeleted())
+ continue;
if (llvm::isa<InstAlloca>(&Instr)) {
// Allocations outside the entry block require a frame pointer.
HasDynamicAllocation = true;
@@ -784,13 +791,15 @@
// Collect the Allocas into the two vectors.
// Allocas in the entry block that have constant size and alignment less
// than or equal to the function's stack alignment.
- CfgVector<Inst *> FixedAllocas;
+ CfgVector<InstAlloca *> FixedAllocas;
// Allocas in the entry block that have constant size and alignment greater
// than the function's stack alignment.
- CfgVector<Inst *> AlignedAllocas;
+ CfgVector<InstAlloca *> AlignedAllocas;
// Maximum alignment used by any alloca.
uint32_t MaxAlignment = StackAlignment;
for (Inst &Instr : EntryNode->getInsts()) {
+ if (Instr.isDeleted())
+ continue;
if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
if (!llvm::isa<Constant>(Alloca->getSizeInBytes()))
continue;
diff --git a/src/IceCfg.h b/src/IceCfg.h
index e3f29c7..c656961 100644
--- a/src/IceCfg.h
+++ b/src/IceCfg.h
@@ -295,7 +295,7 @@
BVT_FramePointer,
BVT_UserPointer
};
- void sortAndCombineAllocas(CfgVector<Inst *> &Allocas,
+ void sortAndCombineAllocas(CfgVector<InstAlloca *> &Allocas,
uint32_t CombinedAlignment, InstList &Insts,
AllocaBaseVariableType BaseVariableType);
void findRematerializable();
diff --git a/src/IceInstrumentation.cpp b/src/IceInstrumentation.cpp
index 64a6212..c911a0b 100644
--- a/src/IceInstrumentation.cpp
+++ b/src/IceInstrumentation.cpp
@@ -51,6 +51,8 @@
std::string FuncName = Func->getFunctionName().toStringOrEmpty();
if (FuncName == "_start")
instrumentStart(Func);
+
+ finishFunc(Func);
}
void Instrumentation::instrumentInst(LoweringContext &Context) {
diff --git a/src/IceInstrumentation.h b/src/IceInstrumentation.h
index 60afef7..3a18542 100644
--- a/src/IceInstrumentation.h
+++ b/src/IceInstrumentation.h
@@ -44,8 +44,10 @@
virtual void instrumentGlobals(VariableDeclarationList &) {}
void instrumentFunc(Cfg *Func);
+protected:
+ virtual void instrumentInst(LoweringContext &Context);
+
private:
- void instrumentInst(LoweringContext &Context);
virtual void instrumentFuncStart(LoweringContext &) {}
virtual void instrumentAlloca(LoweringContext &, class InstAlloca *) {}
virtual void instrumentArithmetic(LoweringContext &, class InstArithmetic *) {
@@ -71,6 +73,7 @@
class InstUnreachable *) {}
virtual void instrumentStart(Cfg *) {}
virtual void instrumentLocalVars(Cfg *) {}
+ virtual void finishFunc(Cfg *) {}
protected:
GlobalContext *Ctx;