|
49 | 49 | #include "llvm/Transforms/Utils/Cloning.h" |
50 | 50 | #include "llvm/Transforms/Utils/Local.h" |
51 | 51 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
| 52 | +#include "llvm/Transforms/Utils/PromoteMemToReg.h" |
52 | 53 | #include <algorithm> |
53 | 54 | #include <string> |
54 | 55 | #include <system_error> |
@@ -165,6 +166,9 @@ static cl::opt<std::string> ClMemoryAccessCallbackPrefix( |
165 | 166 | cl::init("__asan_")); |
166 | 167 | static cl::opt<bool> ClInstrumentAllocas("asan-instrument-allocas", |
167 | 168 | cl::desc("instrument dynamic allocas"), cl::Hidden, cl::init(false)); |
| 169 | +static cl::opt<bool> ClSkipPromotableAllocas("asan-skip-promotable-allocas", |
| 170 | + cl::desc("Do not instrument promotable allocas"), |
| 171 | + cl::Hidden, cl::init(true)); |
168 | 172 |
|
169 | 173 | // These flags allow to change the shadow mapping. |
170 | 174 | // The shadow mapping looks like |
@@ -372,6 +376,17 @@ struct AddressSanitizer : public FunctionPass { |
372 | 376 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
373 | 377 | AU.addRequired<DominatorTreeWrapperPass>(); |
374 | 378 | } |
| 379 | + uint64_t getAllocaSizeInBytes(AllocaInst *AI) const { |
| 380 | + Type *Ty = AI->getAllocatedType(); |
| 381 | + uint64_t SizeInBytes = DL->getTypeAllocSize(Ty); |
| 382 | + return SizeInBytes; |
| 383 | + } |
| 384 | + /// Check if we want (and can) handle this alloca. |
| 385 | + bool isInterestingAlloca(AllocaInst &AI) const; |
| 386 | + /// If it is an interesting memory access, return the PointerOperand |
| 387 | + /// and set IsWrite/Alignment. Otherwise return nullptr. |
| 388 | + Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite, |
| 389 | + unsigned *Alignment) const; |
375 | 390 | void instrumentMop(Instruction *I, bool UseCalls); |
376 | 391 | void instrumentPointerComparisonOrSubtraction(Instruction *I); |
377 | 392 | void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, |
@@ -599,7 +614,7 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { |
599 | 614 |
|
600 | 615 | /// \brief Collect Alloca instructions we want (and can) handle. |
601 | 616 | void visitAllocaInst(AllocaInst &AI) { |
602 | | - if (!isInterestingAlloca(AI)) return; |
| 617 | + if (!ASan.isInterestingAlloca(AI)) return; |
603 | 618 |
|
604 | 619 | StackAlignment = std::max(StackAlignment, AI.getAlignment()); |
605 | 620 | if (isDynamicAlloca(AI)) |
@@ -653,19 +668,6 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { |
653 | 668 | bool isDynamicAlloca(AllocaInst &AI) const { |
654 | 669 | return AI.isArrayAllocation() || !AI.isStaticAlloca(); |
655 | 670 | } |
656 | | - |
657 | | - // Check if we want (and can) handle this alloca. |
658 | | - bool isInterestingAlloca(AllocaInst &AI) const { |
659 | | - return (AI.getAllocatedType()->isSized() && |
660 | | - // alloca() may be called with 0 size, ignore it. |
661 | | - getAllocaSizeInBytes(&AI) > 0); |
662 | | - } |
663 | | - |
664 | | - uint64_t getAllocaSizeInBytes(AllocaInst *AI) const { |
665 | | - Type *Ty = AI->getAllocatedType(); |
666 | | - uint64_t SizeInBytes = ASan.DL->getTypeAllocSize(Ty); |
667 | | - return SizeInBytes; |
668 | | - } |
669 | 671 | /// Finds alloca where the value comes from. |
670 | 672 | AllocaInst *findAllocaForValue(Value *V); |
671 | 673 | void poisonRedZones(ArrayRef<uint8_t> ShadowBytes, IRBuilder<> &IRB, |
@@ -775,38 +777,56 @@ void AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { |
775 | 777 | MI->eraseFromParent(); |
776 | 778 | } |
777 | 779 |
|
778 | | -// If I is an interesting memory access, return the PointerOperand |
779 | | -// and set IsWrite/Alignment. Otherwise return nullptr. |
780 | | -static Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite, |
781 | | - unsigned *Alignment) { |
| 780 | +/// Check if we want (and can) handle this alloca. |
| 781 | +bool AddressSanitizer::isInterestingAlloca(AllocaInst &AI) const { |
| 782 | + return (AI.getAllocatedType()->isSized() && |
| 783 | + // alloca() may be called with 0 size, ignore it. |
| 784 | + getAllocaSizeInBytes(&AI) > 0 && |
| 785 | + // We are only interested in allocas not promotable to registers. |
| 786 | + // Promotable allocas are common under -O0. |
| 787 | + (!ClSkipPromotableAllocas || !isAllocaPromotable(&AI))); |
| 788 | +} |
| 789 | + |
| 790 | +/// If I is an interesting memory access, return the PointerOperand |
| 791 | +/// and set IsWrite/Alignment. Otherwise return nullptr. |
| 792 | +Value *AddressSanitizer::isInterestingMemoryAccess(Instruction *I, |
| 793 | + bool *IsWrite, |
| 794 | + unsigned *Alignment) const { |
782 | 795 | // Skip memory accesses inserted by another instrumentation. |
783 | 796 | if (I->getMetadata("nosanitize")) |
784 | 797 | return nullptr; |
| 798 | + |
| 799 | + Value *PtrOperand = nullptr; |
785 | 800 | if (LoadInst *LI = dyn_cast<LoadInst>(I)) { |
786 | 801 | if (!ClInstrumentReads) return nullptr; |
787 | 802 | *IsWrite = false; |
788 | 803 | *Alignment = LI->getAlignment(); |
789 | | - return LI->getPointerOperand(); |
790 | | - } |
791 | | - if (StoreInst *SI = dyn_cast<StoreInst>(I)) { |
| 804 | + PtrOperand = LI->getPointerOperand(); |
| 805 | + } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { |
792 | 806 | if (!ClInstrumentWrites) return nullptr; |
793 | 807 | *IsWrite = true; |
794 | 808 | *Alignment = SI->getAlignment(); |
795 | | - return SI->getPointerOperand(); |
796 | | - } |
797 | | - if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { |
| 809 | + PtrOperand = SI->getPointerOperand(); |
| 810 | + } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { |
798 | 811 | if (!ClInstrumentAtomics) return nullptr; |
799 | 812 | *IsWrite = true; |
800 | 813 | *Alignment = 0; |
801 | | - return RMW->getPointerOperand(); |
802 | | - } |
803 | | - if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { |
| 814 | + PtrOperand = RMW->getPointerOperand(); |
| 815 | + } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { |
804 | 816 | if (!ClInstrumentAtomics) return nullptr; |
805 | 817 | *IsWrite = true; |
806 | 818 | *Alignment = 0; |
807 | | - return XCHG->getPointerOperand(); |
| 819 | + PtrOperand = XCHG->getPointerOperand(); |
808 | 820 | } |
809 | | - return nullptr; |
| 821 | + |
| 822 | + // Treat memory accesses to promotable allocas as non-interesting since they |
| 823 | + // will not cause memory violations. This greatly speeds up the instrumented |
| 824 | + // executable at -O0. |
| 825 | + if (ClSkipPromotableAllocas) |
| 826 | + if (auto AI = dyn_cast_or_null<AllocaInst>(PtrOperand)) |
| 827 | + return isInterestingAlloca(*AI) ? AI : nullptr; |
| 828 | + |
| 829 | + return PtrOperand; |
810 | 830 | } |
811 | 831 |
|
812 | 832 | static bool isPointerOperand(Value *V) { |
@@ -1665,7 +1685,7 @@ void FunctionStackPoisoner::poisonStack() { |
1665 | 1685 | SVD.reserve(AllocaVec.size()); |
1666 | 1686 | for (AllocaInst *AI : AllocaVec) { |
1667 | 1687 | ASanStackVariableDescription D = { AI->getName().data(), |
1668 | | - getAllocaSizeInBytes(AI), |
| 1688 | + ASan.getAllocaSizeInBytes(AI), |
1669 | 1689 | AI->getAlignment(), AI, 0}; |
1670 | 1690 | SVD.push_back(D); |
1671 | 1691 | } |
@@ -1856,7 +1876,7 @@ void FunctionStackPoisoner::poisonAlloca(Value *V, uint64_t Size, |
1856 | 1876 | AllocaInst *FunctionStackPoisoner::findAllocaForValue(Value *V) { |
1857 | 1877 | if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) |
1858 | 1878 | // We're intested only in allocas we can handle. |
1859 | | - return isInterestingAlloca(*AI) ? AI : nullptr; |
| 1879 | + return ASan.isInterestingAlloca(*AI) ? AI : nullptr; |
1860 | 1880 | // See if we've already calculated (or started to calculate) alloca for a |
1861 | 1881 | // given value. |
1862 | 1882 | AllocaForValueMapTy::iterator I = AllocaForValue.find(V); |
|
0 commit comments