Index: src/IceASanInstrumentation.cpp |
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp |
index f4b47e15f0f42b56d7b47af892026db3519129e1..83ebc193980d0ffe650e3d7662e9754d31a4e6db 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 @@ const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, |
} // 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 @@ ASanInstrumentation::createRz(VariableDeclarationList *List, |
// 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); |
+ 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")); |
- // insert before the current instruction |
- InstList::iterator Next = Context.getNext(); |
- Context.setInsertPoint(Context.getCur()); |
- Context.insert(RzAlloca); |
- Context.setNext(Next); |
-} |
+ InstAlloca *Cur; |
+ ConstantInteger32 *VarSizeOp; |
+ while ( |
+ (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) && |
+ (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) { |
+ HasLocals = true; |
-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); |
-} |
+ // 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); |
-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; |
+ // 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 @@ void ASanInstrumentation::instrumentAccess(LoweringContext &Context, |
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 @@ void ASanInstrumentation::instrumentStart(Cfg *Func) { |
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 |