| OLD | NEW |
| 1 //===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===// | 1 //===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// \brief Implements the AddressSanitizer instrumentation class. | 11 /// \brief Implements the AddressSanitizer instrumentation class. |
| 12 /// | 12 /// |
| 13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
| 14 | 14 |
| 15 #include "IceASanInstrumentation.h" | 15 #include "IceASanInstrumentation.h" |
| 16 | 16 |
| 17 #include "IceBuildDefs.h" | 17 #include "IceBuildDefs.h" |
| 18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
| 19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
| 20 #include "IceGlobalInits.h" | 20 #include "IceGlobalInits.h" |
| 21 #include "IceInst.h" | 21 #include "IceInst.h" |
| 22 #include "IceTargetLowering.h" | 22 #include "IceTargetLowering.h" |
| 23 #include "IceTypes.h" | 23 #include "IceTypes.h" |
| 24 | 24 |
| 25 #include <sstream> | 25 #include <sstream> |
| 26 #include <unordered_map> | 26 #include <unordered_map> |
| 27 #include <vector> |
| 27 | 28 |
| 28 namespace Ice { | 29 namespace Ice { |
| 29 | 30 |
| 30 namespace { | 31 namespace { |
| 32 |
| 31 constexpr SizeT RzSize = 32; | 33 constexpr SizeT RzSize = 32; |
| 32 const std::string RzPrefix = "__$rz"; | 34 const std::string RzPrefix = "__$rz"; |
| 33 const llvm::NaClBitcodeRecord::RecordVector RzContents = | 35 const llvm::NaClBitcodeRecord::RecordVector RzContents = |
| 34 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); | 36 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); |
| 35 | 37 |
| 36 // TODO(tlively): Handle all allocation functions | 38 // TODO(tlively): Handle all allocation functions |
| 37 // In order to instrument the code correctly, the .pexe must not have had its | 39 // In order to instrument the code correctly, the .pexe must not have had its |
| 38 // symbols stripped. | 40 // symbols stripped. |
| 39 using string_map = std::unordered_map<std::string, std::string>; | 41 using string_map = std::unordered_map<std::string, std::string>; |
| 40 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, | 42 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, |
| 41 {"free", "__asan_free"}}; | 43 {"free", "__asan_free"}}; |
| 42 | 44 |
| 43 } // end of anonymous namespace | 45 } // end of anonymous namespace |
| 44 | 46 |
| 47 ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation, |
| 48 LocalDtors); |
| 49 |
| 45 // Create redzones around all global variables, ensuring that the initializer | 50 // Create redzones around all global variables, ensuring that the initializer |
| 46 // types of the redzones and their associated globals match so that they are | 51 // types of the redzones and their associated globals match so that they are |
| 47 // laid out together in memory. | 52 // laid out together in memory. |
| 48 void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { | 53 void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { |
| 49 if (DidInsertRedZones) | 54 if (DidInsertRedZones) |
| 50 return; | 55 return; |
| 51 | 56 |
| 52 VariableDeclarationList NewGlobals; | 57 VariableDeclarationList NewGlobals; |
| 53 // Global holding pointers to all redzones | 58 // Global holding pointers to all redzones |
| 54 auto *RzArray = VariableDeclaration::create(&NewGlobals); | 59 auto *RzArray = VariableDeclaration::create(&NewGlobals); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 Rz->setIsConstant(Global->getIsConstant()); | 124 Rz->setIsConstant(Global->getIsConstant()); |
| 120 RzArray->addInitializer(VariableDeclaration::RelocInitializer::create( | 125 RzArray->addInitializer(VariableDeclaration::RelocInitializer::create( |
| 121 List, Rz, RelocOffsetArray(0))); | 126 List, Rz, RelocOffsetArray(0))); |
| 122 ++RzArraySize; | 127 ++RzArraySize; |
| 123 return Rz; | 128 return Rz; |
| 124 } | 129 } |
| 125 | 130 |
| 126 // Check for an alloca signaling the presence of local variables and add a | 131 // Check for an alloca signaling the presence of local variables and add a |
| 127 // redzone if it is found | 132 // redzone if it is found |
| 128 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { | 133 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { |
| 129 auto *FirstAlloca = llvm::dyn_cast<InstAlloca>(Context.getCur()); | 134 if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) |
| 130 if (FirstAlloca == nullptr) | 135 ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>()); |
| 131 return; | |
| 132 | 136 |
| 133 constexpr SizeT Alignment = 4; | 137 Cfg *Func = Context.getNode()->getCfg(); |
| 134 InstAlloca *RzAlloca = createLocalRz(Context, RzSize, Alignment); | 138 bool HasLocals = false; |
| 139 LoweringContext C; |
| 140 C.init(Context.getNode()); |
| 141 std::vector<Inst *> Initializations; |
| 142 Constant *InitFunc = |
| 143 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_poison")); |
| 144 Constant *DestroyFunc = |
| 145 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_unpoison")); |
| 135 | 146 |
| 136 // insert before the current instruction | 147 InstAlloca *Cur; |
| 137 InstList::iterator Next = Context.getNext(); | 148 ConstantInteger32 *VarSizeOp; |
| 138 Context.setInsertPoint(Context.getCur()); | 149 while ( |
| 139 Context.insert(RzAlloca); | 150 (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) && |
| 140 Context.setNext(Next); | 151 (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) { |
| 141 } | 152 HasLocals = true; |
| 142 | 153 |
| 143 void ASanInstrumentation::instrumentAlloca(LoweringContext &Context, | 154 // create the new alloca that includes a redzone |
| 144 InstAlloca *Instr) { | 155 SizeT VarSize = VarSizeOp->getValue(); |
| 145 auto *VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Instr->getSizeInBytes()); | 156 Variable *Dest = Cur->getDest(); |
| 146 SizeT VarSize = (VarSizeOp == nullptr) ? RzSize : VarSizeOp->getValue(); | 157 SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize); |
| 147 SizeT Padding = Utils::OffsetToAlignment(VarSize, RzSize); | 158 auto *ByteCount = |
| 148 constexpr SizeT Alignment = 1; | 159 ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding); |
| 149 InstAlloca *Rz = createLocalRz(Context, RzSize + Padding, Alignment); | 160 constexpr SizeT Alignment = 8; |
| 150 Context.insert(Rz); | 161 auto *NewVar = InstAlloca::create(Func, Dest, ByteCount, Alignment); |
| 151 } | |
| 152 | 162 |
| 153 InstAlloca *ASanInstrumentation::createLocalRz(LoweringContext &Context, | 163 // calculate the redzone offset |
| 154 SizeT Size, SizeT Alignment) { | 164 Variable *RzLocVar = Func->makeVariable(IceType_i32); |
| 155 Cfg *Func = Context.getNode()->getCfg(); | 165 RzLocVar->setName(Func, nextRzName()); |
| 156 Variable *Rz = Func->makeVariable(IceType_i32); | 166 auto *Offset = ConstantInteger32::create(Ctx, IceType_i32, VarSize); |
| 157 Rz->setName(Func, nextRzName()); | 167 auto *RzLoc = InstArithmetic::create(Func, InstArithmetic::Add, RzLocVar, |
| 158 auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, Size); | 168 Dest, Offset); |
| 159 auto *RzAlloca = InstAlloca::create(Func, Rz, ByteCount, Alignment); | 169 |
| 160 return RzAlloca; | 170 // instructions to poison and unpoison the redzone |
| 171 constexpr SizeT NumArgs = 2; |
| 172 constexpr Variable *Void = nullptr; |
| 173 constexpr bool NoTailcall = false; |
| 174 auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall); |
| 175 auto *Destroy = |
| 176 InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall); |
| 177 Init->addArg(RzLocVar); |
| 178 Destroy->addArg(RzLocVar); |
| 179 auto *RzSizeConst = ConstantInteger32::create(Ctx, IceType_i32, RzPadding); |
| 180 Init->addArg(RzSizeConst); |
| 181 Destroy->addArg(RzSizeConst); |
| 182 |
| 183 Cur->setDeleted(); |
| 184 C.insert(NewVar); |
| 185 ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy); |
| 186 Initializations.emplace_back(RzLoc); |
| 187 Initializations.emplace_back(Init); |
| 188 |
| 189 C.advanceCur(); |
| 190 C.advanceNext(); |
| 191 } |
| 192 |
| 193 C.setInsertPoint(C.getCur()); |
| 194 |
| 195 // add the leftmost redzone |
| 196 if (HasLocals) { |
| 197 Variable *LastRz = Func->makeVariable(IceType_i32); |
| 198 LastRz->setName(Func, nextRzName()); |
| 199 auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, RzSize); |
| 200 constexpr SizeT Alignment = 8; |
| 201 auto *RzAlloca = InstAlloca::create(Func, LastRz, ByteCount, Alignment); |
| 202 |
| 203 constexpr SizeT NumArgs = 2; |
| 204 constexpr Variable *Void = nullptr; |
| 205 constexpr bool NoTailcall = false; |
| 206 auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall); |
| 207 auto *Destroy = |
| 208 InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall); |
| 209 Init->addArg(LastRz); |
| 210 Destroy->addArg(LastRz); |
| 211 Init->addArg(RzAlloca->getSizeInBytes()); |
| 212 Destroy->addArg(RzAlloca->getSizeInBytes()); |
| 213 |
| 214 ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy); |
| 215 C.insert(RzAlloca); |
| 216 C.insert(Init); |
| 217 } |
| 218 |
| 219 // insert initializers for the redzones |
| 220 for (Inst *Init : Initializations) { |
| 221 C.insert(Init); |
| 222 } |
| 161 } | 223 } |
| 162 | 224 |
| 163 void ASanInstrumentation::instrumentCall(LoweringContext &Context, | 225 void ASanInstrumentation::instrumentCall(LoweringContext &Context, |
| 164 InstCall *Instr) { | 226 InstCall *Instr) { |
| 165 auto *CallTarget = | 227 auto *CallTarget = |
| 166 llvm::dyn_cast<ConstantRelocatable>(Instr->getCallTarget()); | 228 llvm::dyn_cast<ConstantRelocatable>(Instr->getCallTarget()); |
| 167 if (CallTarget == nullptr) | 229 if (CallTarget == nullptr) |
| 168 return; | 230 return; |
| 169 | 231 |
| 170 std::string TargetName = CallTarget->getName().toStringOrEmpty(); | 232 std::string TargetName = CallTarget->getName().toStringOrEmpty(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 AccessCheck, NoTailCall); | 269 AccessCheck, NoTailCall); |
| 208 Call->addArg(Op); | 270 Call->addArg(Op); |
| 209 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); | 271 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); |
| 210 // play games to insert the call before the access instruction | 272 // play games to insert the call before the access instruction |
| 211 InstList::iterator Next = Context.getNext(); | 273 InstList::iterator Next = Context.getNext(); |
| 212 Context.setInsertPoint(Context.getCur()); | 274 Context.setInsertPoint(Context.getCur()); |
| 213 Context.insert(Call); | 275 Context.insert(Call); |
| 214 Context.setNext(Next); | 276 Context.setNext(Next); |
| 215 } | 277 } |
| 216 | 278 |
| 279 void ASanInstrumentation::instrumentRet(LoweringContext &Context, |
| 280 InstRet *Instr) { |
| 281 (void)Instr; |
| 282 InstList::iterator Next = Context.getNext(); |
| 283 Context.setInsertPoint(Context.getCur()); |
| 284 for (InstCall *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) { |
| 285 Context.insert(RzUnpoison); |
| 286 } |
| 287 Context.setNext(Next); |
| 288 } |
| 289 |
| 217 void ASanInstrumentation::instrumentStart(Cfg *Func) { | 290 void ASanInstrumentation::instrumentStart(Cfg *Func) { |
| 218 Constant *ShadowMemInit = | 291 Constant *ShadowMemInit = |
| 219 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init")); | 292 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init")); |
| 220 constexpr SizeT NumArgs = 0; | 293 constexpr SizeT NumArgs = 0; |
| 221 constexpr Variable *Void = nullptr; | 294 constexpr Variable *Void = nullptr; |
| 222 constexpr bool NoTailCall = false; | 295 constexpr bool NoTailCall = false; |
| 223 auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall); | 296 auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall); |
| 224 Func->getEntryNode()->getInsts().push_front(Call); | 297 Func->getEntryNode()->getInsts().push_front(Call); |
| 225 } | 298 } |
| 226 | 299 |
| 300 // TODO(tlively): make this more efficient with swap idiom |
| 301 void ASanInstrumentation::finishFunc(Cfg *Func) { |
| 302 (void)Func; |
| 303 ICE_TLS_GET_FIELD(LocalDtors)->clear(); |
| 304 } |
| 305 |
| 227 } // end of namespace Ice | 306 } // end of namespace Ice |
| OLD | NEW |