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 |
(...skipping 23 matching lines...) Expand all Loading... |
34 constexpr const char *ASanPrefix = "__asan"; | 34 constexpr const char *ASanPrefix = "__asan"; |
35 constexpr SizeT RzSize = 32; | 35 constexpr SizeT RzSize = 32; |
36 constexpr const char *RzPrefix = "__$rz"; | 36 constexpr const char *RzPrefix = "__$rz"; |
37 constexpr const char *RzArrayName = "__$rz_array"; | 37 constexpr const char *RzArrayName = "__$rz_array"; |
38 constexpr const char *RzSizesName = "__$rz_sizes"; | 38 constexpr const char *RzSizesName = "__$rz_sizes"; |
39 const llvm::NaClBitcodeRecord::RecordVector RzContents = | 39 const llvm::NaClBitcodeRecord::RecordVector RzContents = |
40 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); | 40 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); |
41 | 41 |
42 // In order to instrument the code correctly, the .pexe must not have had its | 42 // In order to instrument the code correctly, the .pexe must not have had its |
43 // symbols stripped. | 43 // symbols stripped. |
44 using string_map = std::unordered_map<std::string, std::string>; | 44 using StringMap = std::unordered_map<std::string, std::string>; |
45 using string_set = std::unordered_set<std::string>; | 45 using StringSet = std::unordered_set<std::string>; |
46 // TODO(tlively): Handle all allocation functions | 46 // TODO(tlively): Handle all allocation functions |
47 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, | 47 const StringMap FuncSubstitutions = {{"malloc", "__asan_malloc"}, |
48 {"free", "__asan_free"}, | 48 {"free", "__asan_free"}, |
49 {"calloc", "__asan_calloc"}, | 49 {"calloc", "__asan_calloc"}, |
50 {"__asan_dummy_calloc", "__asan_calloc"}, | 50 {"__asan_dummy_calloc", "__asan_calloc"}, |
51 {"realloc", "__asan_realloc"}}; | 51 {"realloc", "__asan_realloc"}}; |
52 const string_set FuncBlackList = {"_Balloc"}; | 52 const StringSet FuncBlackList = {"_Balloc"}; |
53 | 53 |
54 llvm::NaClBitcodeRecord::RecordVector sizeToByteVec(SizeT Size) { | 54 llvm::NaClBitcodeRecord::RecordVector sizeToByteVec(SizeT Size) { |
55 llvm::NaClBitcodeRecord::RecordVector SizeContents; | 55 llvm::NaClBitcodeRecord::RecordVector SizeContents; |
56 for (unsigned i = 0; i < sizeof(Size); ++i) { | 56 for (unsigned i = 0; i < sizeof(Size); ++i) { |
57 SizeContents.emplace_back(Size % (1 << CHAR_BIT)); | 57 SizeContents.emplace_back(Size % (1 << CHAR_BIT)); |
58 Size >>= CHAR_BIT; | 58 Size >>= CHAR_BIT; |
59 } | 59 } |
60 return SizeContents; | 60 return SizeContents; |
61 } | 61 } |
62 | 62 |
63 } // end of anonymous namespace | 63 } // end of anonymous namespace |
64 | 64 |
| 65 ICE_TLS_DEFINE_FIELD(VarSizeMap *, ASanInstrumentation, LocalVars); |
65 ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation, | 66 ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation, |
66 LocalDtors); | 67 LocalDtors); |
67 | 68 |
68 bool ASanInstrumentation::isInstrumentable(Cfg *Func) { | 69 bool ASanInstrumentation::isInstrumentable(Cfg *Func) { |
69 std::string FuncName = Func->getFunctionName().toStringOrEmpty(); | 70 std::string FuncName = Func->getFunctionName().toStringOrEmpty(); |
70 return FuncName == "" || | 71 return FuncName == "" || |
71 (FuncBlackList.count(FuncName) == 0 && FuncName.find(ASanPrefix) != 0); | 72 (FuncBlackList.count(FuncName) == 0 && FuncName.find(ASanPrefix) != 0); |
72 } | 73 } |
73 | 74 |
74 // Create redzones around all global variables, ensuring that the initializer | 75 // Create redzones around all global variables, ensuring that the initializer |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 | 151 |
151 std::string ASanInstrumentation::nextRzName() { | 152 std::string ASanInstrumentation::nextRzName() { |
152 std::stringstream Name; | 153 std::stringstream Name; |
153 Name << RzPrefix << RzNum++; | 154 Name << RzPrefix << RzNum++; |
154 return Name.str(); | 155 return Name.str(); |
155 } | 156 } |
156 | 157 |
157 // Check for an alloca signaling the presence of local variables and add a | 158 // Check for an alloca signaling the presence of local variables and add a |
158 // redzone if it is found | 159 // redzone if it is found |
159 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { | 160 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { |
160 if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) | 161 if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) { |
161 ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>()); | 162 ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>()); |
| 163 ICE_TLS_SET_FIELD(LocalVars, new VarSizeMap()); |
| 164 } |
162 Cfg *Func = Context.getNode()->getCfg(); | 165 Cfg *Func = Context.getNode()->getCfg(); |
163 bool HasLocals = false; | 166 bool HasLocals = false; |
164 LoweringContext C; | 167 LoweringContext C; |
165 C.init(Context.getNode()); | 168 C.init(Context.getNode()); |
166 std::vector<Inst *> Initializations; | 169 std::vector<Inst *> Initializations; |
167 Constant *InitFunc = | 170 Constant *InitFunc = |
168 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_poison")); | 171 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_poison")); |
169 Constant *DestroyFunc = | 172 Constant *DestroyFunc = |
170 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_unpoison")); | 173 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_unpoison")); |
171 | 174 |
172 InstAlloca *Cur; | 175 InstAlloca *Cur; |
173 ConstantInteger32 *VarSizeOp; | 176 ConstantInteger32 *VarSizeOp; |
174 while ( | 177 while ( |
175 (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) && | 178 (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) && |
176 (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) { | 179 (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) { |
177 HasLocals = true; | 180 HasLocals = true; |
178 | 181 |
179 // create the new alloca that includes a redzone | 182 // create the new alloca that includes a redzone |
180 SizeT VarSize = VarSizeOp->getValue(); | 183 SizeT VarSize = VarSizeOp->getValue(); |
181 Variable *Dest = Cur->getDest(); | 184 Variable *Dest = Cur->getDest(); |
| 185 ICE_TLS_GET_FIELD(LocalVars)->insert({Dest, VarSize}); |
182 SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize); | 186 SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize); |
183 auto *ByteCount = | 187 auto *ByteCount = |
184 ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding); | 188 ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding); |
185 constexpr SizeT Alignment = 8; | 189 constexpr SizeT Alignment = 8; |
186 auto *NewVar = InstAlloca::create(Func, Dest, ByteCount, Alignment); | 190 auto *NewVar = InstAlloca::create(Func, Dest, ByteCount, Alignment); |
187 | 191 |
188 // calculate the redzone offset | 192 // calculate the redzone offset |
189 Variable *RzLocVar = Func->makeVariable(IceType_i32); | 193 Variable *RzLocVar = Func->makeVariable(IceType_i32); |
190 RzLocVar->setName(Func, nextRzName()); | 194 RzLocVar->setName(Func, nextRzName()); |
191 auto *Offset = ConstantInteger32::create(Ctx, IceType_i32, VarSize); | 195 auto *Offset = ConstantInteger32::create(Ctx, IceType_i32, VarSize); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 } | 283 } |
280 | 284 |
281 void ASanInstrumentation::instrumentStore(LoweringContext &Context, | 285 void ASanInstrumentation::instrumentStore(LoweringContext &Context, |
282 InstStore *Instr) { | 286 InstStore *Instr) { |
283 Constant *Func = | 287 Constant *Func = |
284 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_check_store")); | 288 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_check_store")); |
285 instrumentAccess(Context, Instr->getAddr(), | 289 instrumentAccess(Context, Instr->getAddr(), |
286 typeWidthInBytes(Instr->getData()->getType()), Func); | 290 typeWidthInBytes(Instr->getData()->getType()), Func); |
287 } | 291 } |
288 | 292 |
289 // TODO(tlively): Take size of access into account as well | |
290 void ASanInstrumentation::instrumentAccess(LoweringContext &Context, | 293 void ASanInstrumentation::instrumentAccess(LoweringContext &Context, |
291 Operand *Op, SizeT Size, | 294 Operand *Op, SizeT Size, |
292 Constant *CheckFunc) { | 295 Constant *CheckFunc) { |
| 296 VarSizeMap::iterator LocalSize = ICE_TLS_GET_FIELD(LocalVars)->find(Op); |
| 297 if (LocalSize != ICE_TLS_GET_FIELD(LocalVars)->end() && |
| 298 LocalSize->second >= Size) |
| 299 return; |
293 constexpr SizeT NumArgs = 2; | 300 constexpr SizeT NumArgs = 2; |
294 constexpr Variable *Void = nullptr; | 301 constexpr Variable *Void = nullptr; |
295 constexpr bool NoTailCall = false; | 302 constexpr bool NoTailCall = false; |
296 auto *Call = InstCall::create(Context.getNode()->getCfg(), NumArgs, Void, | 303 auto *Call = InstCall::create(Context.getNode()->getCfg(), NumArgs, Void, |
297 CheckFunc, NoTailCall); | 304 CheckFunc, NoTailCall); |
298 Call->addArg(Op); | 305 Call->addArg(Op); |
299 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); | 306 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); |
300 // play games to insert the call before the access instruction | 307 // play games to insert the call before the access instruction |
301 InstList::iterator Next = Context.getNext(); | 308 InstList::iterator Next = Context.getNext(); |
302 Context.setInsertPoint(Context.getCur()); | 309 Context.setInsertPoint(Context.getCur()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 | 342 |
336 instrumentGlobals(*getGlobals()); | 343 instrumentGlobals(*getGlobals()); |
337 | 344 |
338 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum)); | 345 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum)); |
339 Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName))); | 346 Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName))); |
340 Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName))); | 347 Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName))); |
341 } | 348 } |
342 | 349 |
343 // TODO(tlively): make this more efficient with swap idiom | 350 // TODO(tlively): make this more efficient with swap idiom |
344 void ASanInstrumentation::finishFunc(Cfg *) { | 351 void ASanInstrumentation::finishFunc(Cfg *) { |
| 352 ICE_TLS_GET_FIELD(LocalVars)->clear(); |
345 ICE_TLS_GET_FIELD(LocalDtors)->clear(); | 353 ICE_TLS_GET_FIELD(LocalDtors)->clear(); |
346 } | 354 } |
347 | 355 |
348 } // end of namespace Ice | 356 } // end of namespace Ice |
OLD | NEW |