|
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