llvm.org GIT mirror llvm / 6ecccdb
[asan] instrument memory accesses with unusual sizes This patch makes asan instrument memory accesses with unusual sizes (e.g. 5 bytes or 10 bytes), e.g. long double or packed structures. Instrumentation is done with two 1-byte checks (first and last bytes) and if the error is found __asan_report_load_n(addr, real_size) or __asan_report_store_n(addr, real_size) is called. Also, call these two new functions in memset/memcpy instrumentation. asan-rt part will follow. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175507 91177308-0d34-0410-b5e6-96231b3b80d8 Kostya Serebryany 6 years ago
2 changed file(s) with 81 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
6363 static const char *kAsanModuleDtorName = "asan.module_dtor";
6464 static const int kAsanCtorAndCtorPriority = 1;
6565 static const char *kAsanReportErrorTemplate = "__asan_report_";
66 static const char *kAsanReportLoadN = "__asan_report_load_n";
67 static const char *kAsanReportStoreN = "__asan_report_store_n";
6668 static const char *kAsanRegisterGlobalsName = "__asan_register_globals";
6769 static const char *kAsanUnregisterGlobalsName = "__asan_unregister_globals";
6870 static const char *kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
256258 return "AddressSanitizerFunctionPass";
257259 }
258260 void instrumentMop(Instruction *I);
259 void instrumentAddress(Instruction *OrigIns, IRBuilder<> &IRB,
260 Value *Addr, uint32_t TypeSize, bool IsWrite);
261 void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
262 Value *Addr, uint32_t TypeSize, bool IsWrite,
263 Value *SizeArgument);
261264 Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
262265 Value *ShadowValue, uint32_t TypeSize);
263266 Instruction *generateCrashCode(Instruction *InsertBefore, Value *Addr,
264 bool IsWrite, size_t AccessSizeIndex);
267 bool IsWrite, size_t AccessSizeIndex,
268 Value *SizeArgument);
265269 bool instrumentMemIntrinsic(MemIntrinsic *MI);
266270 void instrumentMemIntrinsicParam(Instruction *OrigIns, Value *Addr,
267271 Value *Size,
299303 OwningPtr BL;
300304 // This array is indexed by AccessIsWrite and log2(AccessSize).
301305 Function *AsanErrorCallback[2][kNumberOfAccessSizes];
306 // This array is indexed by AccessIsWrite.
307 Function *AsanErrorCallbackSized[2];
302308 InlineAsm *EmptyAsm;
303309 SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals;
304310
547553 void AddressSanitizer::instrumentMemIntrinsicParam(
548554 Instruction *OrigIns,
549555 Value *Addr, Value *Size, Instruction *InsertBefore, bool IsWrite) {
556 IRBuilder<> IRB(InsertBefore);
557 if (Size->getType() != IntptrTy)
558 Size = IRB.CreateIntCast(Size, IntptrTy, false);
550559 // Check the first byte.
551 {
552 IRBuilder<> IRB(InsertBefore);
553 instrumentAddress(OrigIns, IRB, Addr, 8, IsWrite);
554 }
560 instrumentAddress(OrigIns, InsertBefore, Addr, 8, IsWrite, Size);
555561 // Check the last byte.
556 {
557 IRBuilder<> IRB(InsertBefore);
558 Value *SizeMinusOne = IRB.CreateSub(
559 Size, ConstantInt::get(Size->getType(), 1));
560 SizeMinusOne = IRB.CreateIntCast(SizeMinusOne, IntptrTy, false);
561 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
562 Value *AddrPlusSizeMinisOne = IRB.CreateAdd(AddrLong, SizeMinusOne);
563 instrumentAddress(OrigIns, IRB, AddrPlusSizeMinisOne, 8, IsWrite);
564 }
562 IRB.SetInsertPoint(InsertBefore);
563 Value *SizeMinusOne = IRB.CreateSub(Size, ConstantInt::get(IntptrTy, 1));
564 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
565 Value *AddrLast = IRB.CreateAdd(AddrLong, SizeMinusOne);
566 instrumentAddress(OrigIns, InsertBefore, AddrLast, 8, IsWrite, Size);
565567 }
566568
567569 // Instrument memset/memmove/memcpy
640642 assert(OrigTy->isSized());
641643 uint32_t TypeSize = TD->getTypeStoreSizeInBits(OrigTy);
642644
643 if (TypeSize != 8 && TypeSize != 16 &&
644 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
645 // Ignore all unusual sizes.
646 return;
647 }
648
645 assert((TypeSize % 8) == 0);
646
647 // Instrument a 1-, 2-, 4-, 8-, or 16- byte access with one check.
648 if (TypeSize == 8 || TypeSize == 16 ||
649 TypeSize == 32 || TypeSize == 64 || TypeSize == 128)
650 return instrumentAddress(I, I, Addr, TypeSize, IsWrite, 0);
651 // Instrument unusual size (but still multiple of 8).
652 // We can not do it with a single check, so we do 1-byte check for the first
653 // and the last bytes. We call __asan_report_*_n(addr, real_size) to be able
654 // to report the actual access size.
649655 IRBuilder<> IRB(I);
650 instrumentAddress(I, IRB, Addr, TypeSize, IsWrite);
656 Value *LastByte = IRB.CreateIntToPtr(
657 IRB.CreateAdd(IRB.CreatePointerCast(Addr, IntptrTy),
658 ConstantInt::get(IntptrTy, TypeSize / 8 - 1)),
659 OrigPtrTy);
660 Value *Size = ConstantInt::get(IntptrTy, TypeSize / 8);
661 instrumentAddress(I, I, Addr, 8, IsWrite, Size);
662 instrumentAddress(I, I, LastByte, 8, IsWrite, Size);
651663 }
652664
653665 // Validate the result of Module::getOrInsertFunction called for an interface
663675
664676 Instruction *AddressSanitizer::generateCrashCode(
665677 Instruction *InsertBefore, Value *Addr,
666 bool IsWrite, size_t AccessSizeIndex) {
678 bool IsWrite, size_t AccessSizeIndex, Value *SizeArgument) {
667679 IRBuilder<> IRB(InsertBefore);
668 CallInst *Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex],
669 Addr);
680 CallInst *Call = SizeArgument
681 ? IRB.CreateCall2(AsanErrorCallbackSized[IsWrite], Addr, SizeArgument)
682 : IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex], Addr);
683
670684 // We don't do Call->setDoesNotReturn() because the BB already has
671685 // UnreachableInst at the end.
672686 // This EmptyAsm is required to avoid callback merge.
693707 }
694708
695709 void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
696 IRBuilder<> &IRB, Value *Addr,
697 uint32_t TypeSize, bool IsWrite) {
710 Instruction *InsertBefore,
711 Value *Addr, uint32_t TypeSize,
712 bool IsWrite, Value *SizeArgument) {
713 IRBuilder<> IRB(InsertBefore);
698714 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
699715
700716 Type *ShadowTy = IntegerType::get(
726742 CrashTerm = SplitBlockAndInsertIfThen(cast(Cmp), true);
727743 }
728744
729 Instruction *Crash =
730 generateCrashCode(CrashTerm, AddrLong, IsWrite, AccessSizeIndex);
745 Instruction *Crash = generateCrashCode(
746 CrashTerm, AddrLong, IsWrite, AccessSizeIndex, SizeArgument);
731747 Crash->setDebugLoc(OrigIns->getDebugLoc());
732748 }
733749
9961012 FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
9971013 }
9981014 }
1015 AsanErrorCallbackSized[0] = checkInterfaceFunction(M.getOrInsertFunction(
1016 kAsanReportLoadN, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL));
1017 AsanErrorCallbackSized[1] = checkInterfaceFunction(M.getOrInsertFunction(
1018 kAsanReportStoreN, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL));
9991019
10001020 AsanHandleNoReturnFunc = checkInterfaceFunction(M.getOrInsertFunction(
10011021 kAsanHandleNoReturnName, IRB.getVoidTy(), NULL));
9595 }
9696
9797 ; CHECK: LongDoubleTest
98 ; CHECK-NOT: __asan_report_store16
98 ; CHECK: __asan_report_store_n
99 ; CHECK: __asan_report_store_n
99100 ; CHECK: ret void
101
102
103 define void @i40test(i40* %a, i40* %b) nounwind uwtable address_safety {
104 entry:
105 %t = load i40* %a
106 store i40 %t, i40* %b, align 8
107 ret void
108 }
109
110 ; CHECK: i40test
111 ; CHECK: __asan_report_load_n{{.*}}, i64 5)
112 ; CHECK: __asan_report_load_n{{.*}}, i64 5)
113 ; CHECK: __asan_report_store_n{{.*}}, i64 5)
114 ; CHECK: __asan_report_store_n{{.*}}, i64 5)
115 ; CHECK: ret void
116
117 define void @i80test(i80* %a, i80* %b) nounwind uwtable address_safety {
118 entry:
119 %t = load i80* %a
120 store i80 %t, i80* %b, align 8
121 ret void
122 }
123
124 ; CHECK: i80test
125 ; CHECK: __asan_report_load_n{{.*}}, i64 10)
126 ; CHECK: __asan_report_load_n{{.*}}, i64 10)
127 ; CHECK: __asan_report_store_n{{.*}}, i64 10)
128 ; CHECK: __asan_report_store_n{{.*}}, i64 10)
129 ; CHECK: ret void