| 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 | 
|  |