diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -64,7 +64,9 @@ std::function GetSSI; const ModuleSummaryIndex *Index = nullptr; mutable std::unique_ptr Info; + mutable std::unique_ptr> Accesses; const InfoTy &getInfo() const; + const std::map &getAccesses() const; public: StackSafetyGlobalInfo(); @@ -76,6 +78,7 @@ ~StackSafetyGlobalInfo(); bool isSafe(const AllocaInst &AI) const; + bool accessIsSafe(const Instruction *I) const; void print(raw_ostream &O) const; void dump() const; }; diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/ModuleSummaryIndex.h" @@ -30,6 +31,7 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include using namespace llvm; @@ -116,6 +118,7 @@ // Access range if the address (alloca or parameters). // It is allowed to be empty-set when there are no known accesses. ConstantRange Range; + std::map Accesses; // List of calls which pass address as an argument. // Value is offset range of address from base address (alloca or calling @@ -129,6 +132,18 @@ UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); } + void addRange(const Instruction *I, const ConstantRange &R) { + bool Inserted; + std::map::iterator It; + std::tie(It, Inserted) = Accesses.emplace(I, R); + if (!Inserted) { + auto Union = unionNoWrap(It->second, R); + Accesses.erase(It); + std::tie(It, Inserted) = Accesses.emplace(I, Union); + assert(Inserted); + } + updateRange(R); + } }; template @@ -208,7 +223,6 @@ } else { assert(Allocas.empty()); } - O << "\n"; } }; @@ -349,11 +363,11 @@ switch (I->getOpcode()) { case Instruction::Load: { if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } - US.updateRange( - getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType()))); + US.addRange(I, + getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType()))); break; } @@ -363,15 +377,16 @@ case Instruction::Store: { if (V == I->getOperand(0)) { // Stored the pointer - conservatively assume it may be unsafe. - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } - US.updateRange(getAccessRange( - UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType()))); + US.addRange( + I, getAccessRange( + UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType()))); break; } @@ -379,8 +394,8 @@ // Information leak. // FIXME: Process parameters correctly. This is a leak only if we return // alloca. - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; case Instruction::Call: case Instruction::Invoke: { @@ -388,25 +403,26 @@ break; if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } if (const MemIntrinsic *MI = dyn_cast(I)) { - US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr)); + US.addRange(I, getMemIntrinsicAccessRange(MI, UI, Ptr)); break; } const auto &CB = cast(*I); if (!CB.isArgOperand(&UI)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } unsigned ArgNo = CB.getArgOperandNo(&UI); if (CB.isByValArgument(ArgNo)) { - US.updateRange(getAccessRange( - UI, Ptr, DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); + US.addRange(I, getAccessRange( + UI, Ptr, + DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); break; } @@ -416,8 +432,8 @@ const GlobalValue *Callee = dyn_cast(CB.getCalledOperand()->stripPointerCasts()); if (!Callee) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } assert(isa(Callee) || isa(Callee)); @@ -436,7 +452,7 @@ } } - return true; + return !US.Range.isFullSet(); } FunctionInfo StackSafetyLocalAnalysis::run() { @@ -468,7 +484,7 @@ } LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F)); - LLVM_DEBUG(dbgs() << "[StackSafety] done\n"); + LLVM_DEBUG(dbgs() << "\n[StackSafety] done\n"); return Info; } @@ -794,6 +810,29 @@ void StackSafetyInfo::print(raw_ostream &O) const { getInfo().Info.print(O, F->getName(), dyn_cast(F)); + O << "\n"; +} + +const std::map &StackSafetyGlobalInfo::getAccesses() const { + const auto &Info = getInfo(); + if (!Accesses) { + Accesses.reset(new std::map); + for (auto &FnKV : Info.Info) { + for (auto &KV : FnKV.second.Allocas) { + const AllocaInst *AI = KV.first; + auto AIRange = getStaticAllocaSizeRange(*AI); + for (const auto &A : KV.second.Accesses) { + bool IsSafe = AIRange.contains(A.second); + bool Inserted; + std::map::iterator It; + std::tie(It, Inserted) = Accesses->emplace(A.first, IsSafe); + if (!Inserted) + It->second = It->second && IsSafe; + } + } + } + } + return *Accesses; } const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { @@ -811,7 +850,8 @@ for (auto &KV : FnKV.second.Allocas) { ++NumAllocaTotal; const AllocaInst *AI = KV.first; - if (getStaticAllocaSizeRange(*AI).contains(KV.second.Range)) { + auto AIRange = getStaticAllocaSizeRange(*AI); + if (AIRange.contains(KV.second.Range)) { Info->SafeAllocas.insert(AI); ++NumAllocaStackSafe; } @@ -886,6 +926,15 @@ return Info.SafeAllocas.count(&AI); } +bool StackSafetyGlobalInfo::accessIsSafe(const Instruction *I) const { + const auto &Accesses = getAccesses(); + auto It = Accesses.find(I); + if (It != Accesses.end()) { + return It->second; + } + return false; +} + void StackSafetyGlobalInfo::print(raw_ostream &O) const { auto &SSI = getInfo().Info; if (SSI.empty()) @@ -894,6 +943,13 @@ for (auto &F : M.functions()) { if (!F.isDeclaration()) { SSI.find(&F)->second.print(O, F.getName(), &F); + O << " safe accesses:" + << "\n"; + for (const auto &I : instructions(F)) { + if (accessIsSafe(&I)) { + O << " " << I << "\n"; + } + } O << "\n"; } } diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -287,7 +287,7 @@ Instruction *InsertBefore); void instrumentMemIntrinsic(MemIntrinsic *MI); bool instrumentMemAccess(InterestingMemoryOperand &O); - bool ignoreAccess(Value *Ptr); + bool ignoreAccess(Instruction *Inst, Value *Ptr); void getInterestingMemoryOperands( Instruction *I, SmallVectorImpl &Interesting); @@ -768,7 +768,7 @@ } } -bool HWAddressSanitizer::ignoreAccess(Value *Ptr) { +bool HWAddressSanitizer::ignoreAccess(Instruction *Inst, Value *Ptr) { // Do not instrument acesses from different address spaces; we cannot deal // with them. Type *PtrTy = cast(Ptr->getType()->getScalarType()); @@ -782,6 +782,12 @@ if (Ptr->isSwiftError()) return true; + if (!InstrumentStack) { + if (findAllocaForValue(Ptr)) + return true; + } else if (SSI && SSI->accessIsSafe(Inst)) { + return true; + } return false; } @@ -796,29 +802,29 @@ return; if (LoadInst *LI = dyn_cast(I)) { - if (!ClInstrumentReads || ignoreAccess(LI->getPointerOperand())) + if (!ClInstrumentReads || ignoreAccess(I, LI->getPointerOperand())) return; Interesting.emplace_back(I, LI->getPointerOperandIndex(), false, LI->getType(), LI->getAlign()); } else if (StoreInst *SI = dyn_cast(I)) { - if (!ClInstrumentWrites || ignoreAccess(SI->getPointerOperand())) + if (!ClInstrumentWrites || ignoreAccess(I, SI->getPointerOperand())) return; Interesting.emplace_back(I, SI->getPointerOperandIndex(), true, SI->getValueOperand()->getType(), SI->getAlign()); } else if (AtomicRMWInst *RMW = dyn_cast(I)) { - if (!ClInstrumentAtomics || ignoreAccess(RMW->getPointerOperand())) + if (!ClInstrumentAtomics || ignoreAccess(I, RMW->getPointerOperand())) return; Interesting.emplace_back(I, RMW->getPointerOperandIndex(), true, RMW->getValOperand()->getType(), None); } else if (AtomicCmpXchgInst *XCHG = dyn_cast(I)) { - if (!ClInstrumentAtomics || ignoreAccess(XCHG->getPointerOperand())) + if (!ClInstrumentAtomics || ignoreAccess(I, XCHG->getPointerOperand())) return; Interesting.emplace_back(I, XCHG->getPointerOperandIndex(), true, XCHG->getCompareOperand()->getType(), None); } else if (auto CI = dyn_cast(I)) { for (unsigned ArgNo = 0; ArgNo < CI->getNumArgOperands(); ArgNo++) { if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) || - ignoreAccess(CI->getArgOperand(ArgNo))) + ignoreAccess(I, CI->getArgOperand(ArgNo))) continue; Type *Ty = CI->getParamByValType(ArgNo); Interesting.emplace_back(I, ArgNo, false, Ty, Align(1)); diff --git a/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll b/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll @@ -66,6 +66,7 @@ ; GLOBAL-NEXT: x1[1]: full-set, @PreemptableAliasWrite1(arg0, [0,1)){{$}} ; LOCAL-NEXT: x2[1]: empty-set, @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x2[1]: [0,1), @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x1 = alloca i8 @@ -85,6 +86,7 @@ ; LOCAL-NEXT: x[1]: empty-set, @InterposableAliasWrite1(arg0, [0,1)){{$}} ; NOLTO-NEXT: x[1]: full-set, @InterposableAliasWrite1(arg0, [0,1)){{$}} ; LTO-NEXT: x[1]: [0,1), @InterposableAliasWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8 @@ -100,6 +102,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[1]: empty-set, @AliasWrite1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[1]: [0,1), @AliasWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8 @@ -116,6 +119,7 @@ ; GLOBAL-NEXT: x1[4]: [0,1), @BitcastAliasWrite1(arg0, [0,1)){{$}} ; LOCAL-NEXT: x2[1]: empty-set, @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x2[1]: [0,1), @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x1 = alloca i32 @@ -131,4 +135,5 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,1){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: diff --git a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll @@ -126,6 +126,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -141,6 +142,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -156,6 +158,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -171,6 +174,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}} ; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -187,6 +191,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}} ; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -203,6 +208,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -218,6 +224,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -234,6 +241,7 @@ ; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}} ; NOLTO-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}} ; LTO-NEXT: x[4]: [0,1), @InterposableWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -249,6 +257,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -262,6 +271,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,1){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: store i8 0, i8* %p, align 1 @@ -276,6 +286,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -290,6 +301,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}} ; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -306,6 +318,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}} ; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -322,6 +335,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}} ; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -338,6 +352,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}} ; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -354,6 +369,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}} ; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -369,6 +385,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}} ; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -384,6 +401,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}} ; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -400,6 +418,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}} ; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -417,6 +436,9 @@ ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i32 0, i32* %sum, align 4 +; GLOBAL-NEXT: %1 = load i32, i32* %sum, align 4 ; CHECK-EMPTY: entry: %sum = alloca i32, align 4 @@ -433,6 +455,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}} ; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %sum = alloca i32, i64 16, align 4 @@ -447,6 +470,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, i64 16, align 4 @@ -460,6 +484,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: y[1]: empty-set, @Write1SameModule(arg0, [0,1)){{$}} ; GLOBAL-NEXT: y[1]: [0,1), @Write1SameModule(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %y = alloca i8, align 4 @@ -473,6 +498,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: z[1]: empty-set, @Write1DiffModule(arg0, [0,1)){{$}} ; GLOBAL-NEXT: z[1]: [0,1), @Write1DiffModule(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %z = alloca i8, align 4 @@ -486,6 +512,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[1]: empty-set, @Write1Private(arg0, [0,1)){{$}} ; GLOBAL-NEXT: x[1]: [-1,0), @Write1Private(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -501,6 +528,7 @@ ; LOCAL-NEXT: x[1]: empty-set, @Write1Weak(arg0, [0,1)){{$}} ; NOLTO-NEXT: x[1]: [1,2), @Write1Weak(arg0, [0,1)){{$}} ; LTO-NEXT: x[1]: full-set, @Write1Weak(arg0, [0,1)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -534,12 +562,14 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,1){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Write4{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,4){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Write4_2{{$}} @@ -547,36 +577,42 @@ ; CHECK-NEXT: p[]: [0,4){{$}} ; CHECK-NEXT: q[]: [0,4){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Write8{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,8){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @WriteAndReturn8{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: full-set{{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,1){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @InterposableWrite1 interposable{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [0,1){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @ReturnDependent{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: full-set{{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Rec0{{$}} @@ -584,6 +620,7 @@ ; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}} ; GLOBAL-NEXT: p[]: [2,6) ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Rec1{{$}} @@ -591,6 +628,7 @@ ; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}} ; GLOBAL-NEXT: p[]: [3,7) ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @Rec2{{$}} @@ -598,6 +636,7 @@ ; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}} ; GLOBAL-NEXT: p[]: [-2,2) ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @RecursiveNoOffset{{$}} @@ -606,6 +645,7 @@ ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}} ; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @RecursiveWithOffset{{$}} @@ -613,12 +653,14 @@ ; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}} ; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}} ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; CHECK-LABEL: @ReturnAlloca ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: full-set +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: ; INDEX-LABEL: ^0 = module: diff --git a/llvm/test/Analysis/StackSafetyAnalysis/local.ll b/llvm/test/Analysis/StackSafetyAnalysis/local.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/local.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/local.ll @@ -17,6 +17,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -30,6 +31,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,1){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i8 0, i8* %x1, align 1 ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -43,6 +46,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i32 0, i32* %x, align 4 ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -55,6 +60,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [2,3){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i8 0, i8* %x2, align 1 ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -70,6 +77,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -85,6 +93,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: full-set ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %p1 = getelementptr i8, i8* %p, i64 9223372036854775805 @@ -99,6 +108,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806) ; CHECK-NEXT: allocas uses: +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: call void @llvm.memset.p0i8.i64(i8* %p, i8 1, i64 9223372036854775806, i1 0) @@ -112,6 +122,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [2,6){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -128,6 +139,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,1){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: %v = load i8, i8* %x1, align 1 ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -141,6 +154,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [2,6){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -157,6 +171,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -173,6 +188,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}} ; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -190,6 +206,7 @@ ; CHECK-NEXT: p[]: full-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -204,6 +221,8 @@ ; CHECK-NEXT: allocas uses: ; FIXME: SCEV can't look through selects. ; CHECK-NEXT: x[4]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i8 0, i8* %x2, align 1 ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -219,6 +238,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, i32 10, align 4 @@ -232,6 +252,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[40]: [-131072,131072){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, i32 10, align 4 @@ -245,6 +266,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,6){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -260,6 +282,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[40]: [36,40){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i32 0, i32* %x3, align 1 ; CHECK-EMPTY: entry: %x = alloca i32, i32 10, align 4 @@ -275,6 +299,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[40]: [37,41){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, i32 10, align 4 @@ -290,6 +315,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: empty-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, i64 %size, align 16 @@ -302,6 +328,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, i64 %size, align 16 @@ -316,6 +343,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %size = select i1 %z, i64 3, i64 5 @@ -329,6 +357,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[10]: [0,10){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: %1 = load volatile i8, i8* %p.09, align 1 ; CHECK-EMPTY: entry: %x = alloca [10 x i8], align 1 @@ -355,6 +385,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[10]: [0,11){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca [10 x i8], align 1 @@ -381,6 +412,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x1[128]: [0,4294967295){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x1 = alloca [128 x i8], align 16 @@ -405,6 +437,7 @@ ; CHECK-NEXT: unused[]: empty-set ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,1){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca , align 4 @@ -422,6 +455,8 @@ ; CHECK-NEXT: p[]: empty-set ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: empty-set +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store %zerosize_type undef, %zerosize_type* %x, align 4 ; CHECK-EMPTY: entry: %x = alloca %zerosize_type, align 4 @@ -436,6 +471,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: a[4]: full-set +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %a = alloca i32, align 4 @@ -447,6 +483,7 @@ ; CHECK-LABEL: @ByVal dso_preemptable{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: + ; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: ret void @@ -458,6 +495,9 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[2]: [0,2) ; CHECK-NEXT: y[8]: [0,2) +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: call void @ByVal(i16* byval(i16) %x) +; GLOBAL-NEXT: call void @ByVal(i16* byval(i16) %y1) ; CHECK-EMPTY: entry: %x = alloca i16, align 4 @@ -477,6 +517,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: z[800000]: [500000,1300000) +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %z = alloca [100000 x i64], align 4 @@ -492,6 +533,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}} ; CHECK-NEXT: allocas uses: + ; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: %p2 = getelementptr i8, i8* %p, i64 -9223372036854775808 %v = load i8, i8* %p2, align 1 @@ -504,6 +546,7 @@ ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}} ; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -518,6 +561,7 @@ ; CHECK-NEXT: p[]: empty-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[1]: empty-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -539,6 +583,7 @@ ; CHECK: x[1]: full-set{{$}} ; CHECK: y[1]: full-set{{$}} ; CHECK: z[1]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -563,6 +608,10 @@ ; CHECK: x[1]: [0,1){{$}} ; CHECK: y[1]: [0,1){{$}} ; CHECK: z[1]: [0,1){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: store i8 5, i8* %x +; GLOBAL-NEXT: %n = load i8, i8* %y +; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false) ; CHECK-EMPTY: entry: %x = alloca i8, align 4 @@ -587,6 +636,7 @@ ; CHECK: x[1]: full-set{{$}} ; CHECK: y[1]: full-set{{$}} ; CHECK: z[1]: full-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i8, align 4 diff --git a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll @@ -1,5 +1,5 @@ ; RUN: opt -S -passes="print" -disable-output < %s 2>&1 | FileCheck %s -; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -14,6 +14,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false) ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -28,6 +30,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true) ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -41,6 +45,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,5){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -54,6 +59,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4294967295){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -69,6 +75,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,7){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -84,6 +91,7 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4294967295){{$}} ; CHECK-NEXT: y[4]: empty-set{{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -102,6 +110,8 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4){{$}} ; CHECK-NEXT: y[4]: [0,4){{$}} +; GLOBAL-NEXT: safe accesses: +; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false) ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -118,6 +128,7 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: [0,5){{$}} ; CHECK-NEXT: y[4]: [0,5){{$}} +; GLOBAL-NEXT: safe accesses ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -134,6 +145,7 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,5){{$}} ; CHECK-NEXT: y[8]: [0,5){{$}} +; GLOBAL-NEXT: safe accesses ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -150,6 +162,7 @@ ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,9){{$}} ; CHECK-NEXT: y[8]: [0,9){{$}} +; GLOBAL-NEXT: safe accesses ; CHECK-EMPTY: entry: %x = alloca i32, align 4 @@ -165,6 +178,8 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: [0,8){{$}} +; GLOBAL-NEXT: safe accesses +; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false) ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -179,6 +194,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: [0,9){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -193,6 +209,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: [0,9){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 @@ -207,6 +224,7 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[8]: [0,14){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca i64, align 4 diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/memaccess-clobber.ll b/llvm/test/Instrumentation/HWAddressSanitizer/memaccess-clobber.ll --- a/llvm/test/Instrumentation/HWAddressSanitizer/memaccess-clobber.ll +++ b/llvm/test/Instrumentation/HWAddressSanitizer/memaccess-clobber.ll @@ -1,6 +1,6 @@ ; Make sure memaccess checks preceed the following reads. ; -; RUN: opt < %s -S -enable-new-pm=0 -hwasan -basic-aa -memdep -print-memdeps -analyze -mtriple aarch64-linux-android30 | FileCheck %s +; RUN: opt < %s -S -enable-new-pm=0 -hwasan -hwasan-use-stack-safety=0 -basic-aa -memdep -print-memdeps -analyze -mtriple aarch64-linux-android30 | FileCheck %s target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64--linux-android10000" diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll --- a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll +++ b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll @@ -1,15 +1,21 @@ -; RUN: opt -passes=hwasan -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY -; RUN: opt -passes=hwasan -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY -; RUN: opt -passes=hwasan -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-stack=0 -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSTACK,CHECK target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64-unknown-linux-gnu" ; Check a safe alloca to ensure it does not get a tag. -define i32 @test_load(i32* %a) sanitize_hwaddress { +define i32 @test_simple(i32* %a) sanitize_hwaddress { entry: + ; CHECK-LABEL: @test_simple ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store %buf.sroa.0 = alloca i8, align 4 call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0) store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8 @@ -20,8 +26,13 @@ ; Check a non-safe alloca to ensure it gets a tag. define i32 @test_use(i32* %a) sanitize_hwaddress { entry: + ; CHECK-LABEL: @test_use ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store %buf.sroa.0 = alloca i8, align 4 call void @use(i8* nonnull %buf.sroa.0) call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0) @@ -30,13 +41,130 @@ ret i32 0 } +; Check an alloca with in range GEP to ensure it does not get a tag or check. +define i32 @test_in_range(i32* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr) + ret i32 0 +} + +; Check an alloca with in range GEP to ensure it does not get a tag or check. +define i32 @test_in_range2(i32* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range2 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9 + %x = bitcast [10 x i8]* %buf.sroa.0 to i8* + call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %x) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %x) + ret i32 0 +} + +; Check an alloca with out of range GEP to ensure it gets a tag and check. +define i32 @test_out_of_range(i32* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_out_of_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 10 + %x = bitcast [10 x i8]* %buf.sroa.0 to i8* + call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %x) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %x) + ret i32 0 +} + +; Check an alloca with potentially out of range GEP to ensure it gets a tag and +; check. +define i32 @test_potentially_out_of_range(i32* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_potentially_out_of_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %off = call i32 @getoffset() + %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 %off + call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr) + ret i32 0 +} + +; Check an alloca with potentially out of range GEP to ensure it gets a tag and +; check. +define i32 @test_unclear(i32* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_unclear + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca i8, align 4 + %ptr = call i8* @getptr(i8* %buf.sroa.0) + call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr) + ret i32 0 +} + +define i32 @test_select(i8* %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_select + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_store + %x = call i8* @getptr(i8* %a) + %buf.sroa.0 = alloca i8, align 4 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0) + %c = call i1 @cond() + %ptr = select i1 %c, i8* %x, i8* %buf.sroa.0 + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0) + ret i32 0 +} + ; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) ; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) +declare i1 @cond() declare void @use(i8* nocapture) +declare i32 @getoffset() +declare i8* @getptr(i8* nocapture) !8 = !{!9, !9, i64 0} !9 = !{!"omnipotent char", !10, i64 0}