1 //===- StackSafetyAnalysis.cpp - Stack memory safety analysis -------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "llvm/Analysis/StackSafetyAnalysis.h"
12 #include "llvm/ADT/APInt.h"
13 #include "llvm/ADT/SmallPtrSet.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/Statistic.h"
16 #include "llvm/Analysis/ModuleSummaryAnalysis.h"
17 #include "llvm/Analysis/ScalarEvolution.h"
18 #include "llvm/Analysis/StackLifetime.h"
19 #include "llvm/IR/ConstantRange.h"
20 #include "llvm/IR/DerivedTypes.h"
21 #include "llvm/IR/GlobalValue.h"
22 #include "llvm/IR/InstIterator.h"
23 #include "llvm/IR/Instruction.h"
24 #include "llvm/IR/Instructions.h"
25 #include "llvm/IR/IntrinsicInst.h"
26 #include "llvm/IR/ModuleSummaryIndex.h"
27 #include "llvm/InitializePasses.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/FormatVariadic.h"
31 #include "llvm/Support/raw_ostream.h"
38 #define DEBUG_TYPE "stack-safety"
40 STATISTIC(NumAllocaStackSafe
, "Number of safe allocas");
41 STATISTIC(NumAllocaTotal
, "Number of total allocas");
43 STATISTIC(NumCombinedCalleeLookupTotal
,
44 "Number of total callee lookups on combined index.");
45 STATISTIC(NumCombinedCalleeLookupFailed
,
46 "Number of failed callee lookups on combined index.");
47 STATISTIC(NumModuleCalleeLookupTotal
,
48 "Number of total callee lookups on module index.");
49 STATISTIC(NumModuleCalleeLookupFailed
,
50 "Number of failed callee lookups on module index.");
51 STATISTIC(NumCombinedParamAccessesBefore
,
52 "Number of total param accesses before generateParamAccessSummary.");
53 STATISTIC(NumCombinedParamAccessesAfter
,
54 "Number of total param accesses after generateParamAccessSummary.");
55 STATISTIC(NumCombinedDataFlowNodes
,
56 "Number of total nodes in combined index for dataflow processing.");
57 STATISTIC(NumIndexCalleeUnhandled
, "Number of index callee which are unhandled.");
58 STATISTIC(NumIndexCalleeMultipleWeak
, "Number of index callee non-unique weak.");
59 STATISTIC(NumIndexCalleeMultipleExternal
, "Number of index callee non-unique external.");
62 static cl::opt
<int> StackSafetyMaxIterations("stack-safety-max-iterations",
63 cl::init(20), cl::Hidden
);
65 static cl::opt
<bool> StackSafetyPrint("stack-safety-print", cl::init(false),
68 static cl::opt
<bool> StackSafetyRun("stack-safety-run", cl::init(false),
73 // Check if we should bailout for such ranges.
74 bool isUnsafe(const ConstantRange
&R
) {
75 return R
.isEmptySet() || R
.isFullSet() || R
.isUpperSignWrapped();
78 ConstantRange
addOverflowNever(const ConstantRange
&L
, const ConstantRange
&R
) {
79 assert(!L
.isSignWrappedSet());
80 assert(!R
.isSignWrappedSet());
81 if (L
.signedAddMayOverflow(R
) !=
82 ConstantRange::OverflowResult::NeverOverflows
)
83 return ConstantRange::getFull(L
.getBitWidth());
84 ConstantRange Result
= L
.add(R
);
85 assert(!Result
.isSignWrappedSet());
89 ConstantRange
unionNoWrap(const ConstantRange
&L
, const ConstantRange
&R
) {
90 assert(!L
.isSignWrappedSet());
91 assert(!R
.isSignWrappedSet());
92 auto Result
= L
.unionWith(R
);
93 // Two non-wrapped sets can produce wrapped.
94 if (Result
.isSignWrappedSet())
95 Result
= ConstantRange::getFull(Result
.getBitWidth());
99 /// Describes use of address in as a function call argument.
100 template <typename CalleeTy
> struct CallInfo
{
101 /// Function being called.
102 const CalleeTy
*Callee
= nullptr;
103 /// Index of argument which pass address.
106 CallInfo(const CalleeTy
*Callee
, size_t ParamNo
)
107 : Callee(Callee
), ParamNo(ParamNo
) {}
110 bool operator()(const CallInfo
&L
, const CallInfo
&R
) const {
111 return std::tie(L
.ParamNo
, L
.Callee
) < std::tie(R
.ParamNo
, R
.Callee
);
116 /// Describe uses of address (alloca or parameter) inside of the function.
117 template <typename CalleeTy
> struct UseInfo
{
118 // Access range if the address (alloca or parameters).
119 // It is allowed to be empty-set when there are no known accesses.
121 std::set
<const Instruction
*> UnsafeAccesses
;
123 // List of calls which pass address as an argument.
124 // Value is offset range of address from base address (alloca or calling
125 // function argument). Range should never set to empty-set, that is an invalid
126 // access range that can cause empty-set to be propagated with
127 // ConstantRange::add
128 using CallsTy
= std::map
<CallInfo
<CalleeTy
>, ConstantRange
,
129 typename CallInfo
<CalleeTy
>::Less
>;
132 UseInfo(unsigned PointerSize
) : Range
{PointerSize
, false} {}
134 void updateRange(const ConstantRange
&R
) { Range
= unionNoWrap(Range
, R
); }
135 void addRange(const Instruction
*I
, const ConstantRange
&R
, bool IsSafe
) {
137 UnsafeAccesses
.insert(I
);
142 template <typename CalleeTy
>
143 raw_ostream
&operator<<(raw_ostream
&OS
, const UseInfo
<CalleeTy
> &U
) {
145 for (auto &Call
: U
.Calls
)
147 << "@" << Call
.first
.Callee
->getName() << "(arg" << Call
.first
.ParamNo
148 << ", " << Call
.second
<< ")";
152 /// Calculate the allocation size of a given alloca. Returns empty range
153 // in case of confution.
154 ConstantRange
getStaticAllocaSizeRange(const AllocaInst
&AI
) {
155 const DataLayout
&DL
= AI
.getModule()->getDataLayout();
156 TypeSize TS
= DL
.getTypeAllocSize(AI
.getAllocatedType());
157 unsigned PointerSize
= DL
.getPointerTypeSizeInBits(AI
.getType());
158 // Fallback to empty range for alloca size.
159 ConstantRange R
= ConstantRange::getEmpty(PointerSize
);
162 APInt
APSize(PointerSize
, TS
.getFixedValue(), true);
163 if (APSize
.isNonPositive())
165 if (AI
.isArrayAllocation()) {
166 const auto *C
= dyn_cast
<ConstantInt
>(AI
.getArraySize());
169 bool Overflow
= false;
170 APInt Mul
= C
->getValue();
171 if (Mul
.isNonPositive())
173 Mul
= Mul
.sextOrTrunc(PointerSize
);
174 APSize
= APSize
.smul_ov(Mul
, Overflow
);
178 R
= ConstantRange(APInt::getZero(PointerSize
), APSize
);
179 assert(!isUnsafe(R
));
183 template <typename CalleeTy
> struct FunctionInfo
{
184 std::map
<const AllocaInst
*, UseInfo
<CalleeTy
>> Allocas
;
185 std::map
<uint32_t, UseInfo
<CalleeTy
>> Params
;
186 // TODO: describe return value as depending on one or more of its arguments.
188 // StackSafetyDataFlowAnalysis counter stored here for faster access.
191 void print(raw_ostream
&O
, StringRef Name
, const Function
*F
) const {
192 // TODO: Consider different printout format after
193 // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then.
194 O
<< " @" << Name
<< ((F
&& F
->isDSOLocal()) ? "" : " dso_preemptable")
195 << ((F
&& F
->isInterposable()) ? " interposable" : "") << "\n";
197 O
<< " args uses:\n";
198 for (auto &KV
: Params
) {
201 O
<< F
->getArg(KV
.first
)->getName();
203 O
<< formatv("arg{0}", KV
.first
);
204 O
<< "[]: " << KV
.second
<< "\n";
207 O
<< " allocas uses:\n";
209 for (const auto &I
: instructions(F
)) {
210 if (const AllocaInst
*AI
= dyn_cast
<AllocaInst
>(&I
)) {
211 auto &AS
= Allocas
.find(AI
)->second
;
212 O
<< " " << AI
->getName() << "["
213 << getStaticAllocaSizeRange(*AI
).getUpper() << "]: " << AS
<< "\n";
217 assert(Allocas
.empty());
222 using GVToSSI
= std::map
<const GlobalValue
*, FunctionInfo
<GlobalValue
>>;
226 struct StackSafetyInfo::InfoTy
{
227 FunctionInfo
<GlobalValue
> Info
;
230 struct StackSafetyGlobalInfo::InfoTy
{
232 SmallPtrSet
<const AllocaInst
*, 8> SafeAllocas
;
233 std::set
<const Instruction
*> UnsafeAccesses
;
238 class StackSafetyLocalAnalysis
{
240 const DataLayout
&DL
;
242 unsigned PointerSize
= 0;
244 const ConstantRange UnknownRange
;
246 ConstantRange
offsetFrom(Value
*Addr
, Value
*Base
);
247 ConstantRange
getAccessRange(Value
*Addr
, Value
*Base
,
248 const ConstantRange
&SizeRange
);
249 ConstantRange
getAccessRange(Value
*Addr
, Value
*Base
, TypeSize Size
);
250 ConstantRange
getMemIntrinsicAccessRange(const MemIntrinsic
*MI
, const Use
&U
,
253 void analyzeAllUses(Value
*Ptr
, UseInfo
<GlobalValue
> &AS
,
254 const StackLifetime
&SL
);
257 bool isSafeAccess(const Use
&U
, AllocaInst
*AI
, const SCEV
*AccessSize
);
258 bool isSafeAccess(const Use
&U
, AllocaInst
*AI
, Value
*V
);
259 bool isSafeAccess(const Use
&U
, AllocaInst
*AI
, TypeSize AccessSize
);
262 StackSafetyLocalAnalysis(Function
&F
, ScalarEvolution
&SE
)
263 : F(F
), DL(F
.getParent()->getDataLayout()), SE(SE
),
264 PointerSize(DL
.getPointerSizeInBits()),
265 UnknownRange(PointerSize
, true) {}
267 // Run the transformation on the associated function.
268 FunctionInfo
<GlobalValue
> run();
271 ConstantRange
StackSafetyLocalAnalysis::offsetFrom(Value
*Addr
, Value
*Base
) {
272 if (!SE
.isSCEVable(Addr
->getType()) || !SE
.isSCEVable(Base
->getType()))
275 auto *PtrTy
= PointerType::getUnqual(SE
.getContext());
276 const SCEV
*AddrExp
= SE
.getTruncateOrZeroExtend(SE
.getSCEV(Addr
), PtrTy
);
277 const SCEV
*BaseExp
= SE
.getTruncateOrZeroExtend(SE
.getSCEV(Base
), PtrTy
);
278 const SCEV
*Diff
= SE
.getMinusSCEV(AddrExp
, BaseExp
);
279 if (isa
<SCEVCouldNotCompute
>(Diff
))
282 ConstantRange Offset
= SE
.getSignedRange(Diff
);
283 if (isUnsafe(Offset
))
285 return Offset
.sextOrTrunc(PointerSize
);
289 StackSafetyLocalAnalysis::getAccessRange(Value
*Addr
, Value
*Base
,
290 const ConstantRange
&SizeRange
) {
291 // Zero-size loads and stores do not access memory.
292 if (SizeRange
.isEmptySet())
293 return ConstantRange::getEmpty(PointerSize
);
294 assert(!isUnsafe(SizeRange
));
296 ConstantRange Offsets
= offsetFrom(Addr
, Base
);
297 if (isUnsafe(Offsets
))
300 Offsets
= addOverflowNever(Offsets
, SizeRange
);
301 if (isUnsafe(Offsets
))
306 ConstantRange
StackSafetyLocalAnalysis::getAccessRange(Value
*Addr
, Value
*Base
,
308 if (Size
.isScalable())
310 APInt
APSize(PointerSize
, Size
.getFixedValue(), true);
311 if (APSize
.isNegative())
313 return getAccessRange(Addr
, Base
,
314 ConstantRange(APInt::getZero(PointerSize
), APSize
));
317 ConstantRange
StackSafetyLocalAnalysis::getMemIntrinsicAccessRange(
318 const MemIntrinsic
*MI
, const Use
&U
, Value
*Base
) {
319 if (const auto *MTI
= dyn_cast
<MemTransferInst
>(MI
)) {
320 if (MTI
->getRawSource() != U
&& MTI
->getRawDest() != U
)
321 return ConstantRange::getEmpty(PointerSize
);
323 if (MI
->getRawDest() != U
)
324 return ConstantRange::getEmpty(PointerSize
);
327 auto *CalculationTy
= IntegerType::getIntNTy(SE
.getContext(), PointerSize
);
328 if (!SE
.isSCEVable(MI
->getLength()->getType()))
332 SE
.getTruncateOrZeroExtend(SE
.getSCEV(MI
->getLength()), CalculationTy
);
333 ConstantRange Sizes
= SE
.getSignedRange(Expr
);
334 if (!Sizes
.getUpper().isStrictlyPositive() || isUnsafe(Sizes
))
336 Sizes
= Sizes
.sextOrTrunc(PointerSize
);
337 ConstantRange
SizeRange(APInt::getZero(PointerSize
), Sizes
.getUpper() - 1);
338 return getAccessRange(U
, Base
, SizeRange
);
341 bool StackSafetyLocalAnalysis::isSafeAccess(const Use
&U
, AllocaInst
*AI
,
343 return isSafeAccess(U
, AI
, SE
.getSCEV(V
));
346 bool StackSafetyLocalAnalysis::isSafeAccess(const Use
&U
, AllocaInst
*AI
,
350 auto *CalculationTy
= IntegerType::getIntNTy(SE
.getContext(), PointerSize
);
351 const SCEV
*SV
= SE
.getConstant(CalculationTy
, TS
.getFixedValue());
352 return isSafeAccess(U
, AI
, SV
);
355 bool StackSafetyLocalAnalysis::isSafeAccess(const Use
&U
, AllocaInst
*AI
,
356 const SCEV
*AccessSize
) {
359 return true; // This only judges whether it is a safe *stack* access.
360 if (isa
<SCEVCouldNotCompute
>(AccessSize
))
363 const auto *I
= cast
<Instruction
>(U
.getUser());
365 auto ToCharPtr
= [&](const SCEV
*V
) {
366 auto *PtrTy
= PointerType::getUnqual(SE
.getContext());
367 return SE
.getTruncateOrZeroExtend(V
, PtrTy
);
370 const SCEV
*AddrExp
= ToCharPtr(SE
.getSCEV(U
.get()));
371 const SCEV
*BaseExp
= ToCharPtr(SE
.getSCEV(AI
));
372 const SCEV
*Diff
= SE
.getMinusSCEV(AddrExp
, BaseExp
);
373 if (isa
<SCEVCouldNotCompute
>(Diff
))
376 auto Size
= getStaticAllocaSizeRange(*AI
);
378 auto *CalculationTy
= IntegerType::getIntNTy(SE
.getContext(), PointerSize
);
379 auto ToDiffTy
= [&](const SCEV
*V
) {
380 return SE
.getTruncateOrZeroExtend(V
, CalculationTy
);
382 const SCEV
*Min
= ToDiffTy(SE
.getConstant(Size
.getLower()));
383 const SCEV
*Max
= SE
.getMinusSCEV(ToDiffTy(SE
.getConstant(Size
.getUpper())),
384 ToDiffTy(AccessSize
));
385 return SE
.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SGE
, Diff
, Min
, I
)
387 SE
.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SLE
, Diff
, Max
, I
)
391 /// The function analyzes all local uses of Ptr (alloca or argument) and
392 /// calculates local access range and all function calls where it was used.
393 void StackSafetyLocalAnalysis::analyzeAllUses(Value
*Ptr
,
394 UseInfo
<GlobalValue
> &US
,
395 const StackLifetime
&SL
) {
396 SmallPtrSet
<const Value
*, 16> Visited
;
397 SmallVector
<const Value
*, 8> WorkList
;
398 WorkList
.push_back(Ptr
);
399 AllocaInst
*AI
= dyn_cast
<AllocaInst
>(Ptr
);
401 // A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc.
402 while (!WorkList
.empty()) {
403 const Value
*V
= WorkList
.pop_back_val();
404 for (const Use
&UI
: V
->uses()) {
405 const auto *I
= cast
<Instruction
>(UI
.getUser());
406 if (!SL
.isReachable(I
))
409 assert(V
== UI
.get());
411 auto RecordStore
= [&](const Value
* StoredVal
) {
412 if (V
== StoredVal
) {
413 // Stored the pointer - conservatively assume it may be unsafe.
414 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
417 if (AI
&& !SL
.isAliveAfter(AI
, I
)) {
418 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
421 auto TypeSize
= DL
.getTypeStoreSize(StoredVal
->getType());
422 auto AccessRange
= getAccessRange(UI
, Ptr
, TypeSize
);
423 bool Safe
= isSafeAccess(UI
, AI
, TypeSize
);
424 US
.addRange(I
, AccessRange
, Safe
);
428 switch (I
->getOpcode()) {
429 case Instruction::Load
: {
430 if (AI
&& !SL
.isAliveAfter(AI
, I
)) {
431 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
434 auto TypeSize
= DL
.getTypeStoreSize(I
->getType());
435 auto AccessRange
= getAccessRange(UI
, Ptr
, TypeSize
);
436 bool Safe
= isSafeAccess(UI
, AI
, TypeSize
);
437 US
.addRange(I
, AccessRange
, Safe
);
441 case Instruction::VAArg
:
442 // "va-arg" from a pointer is safe.
444 case Instruction::Store
:
445 RecordStore(cast
<StoreInst
>(I
)->getValueOperand());
447 case Instruction::AtomicCmpXchg
:
448 RecordStore(cast
<AtomicCmpXchgInst
>(I
)->getNewValOperand());
450 case Instruction::AtomicRMW
:
451 RecordStore(cast
<AtomicRMWInst
>(I
)->getValOperand());
454 case Instruction::Ret
:
456 // FIXME: Process parameters correctly. This is a leak only if we return
458 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
461 case Instruction::Call
:
462 case Instruction::Invoke
: {
463 if (I
->isLifetimeStartOrEnd())
466 if (AI
&& !SL
.isAliveAfter(AI
, I
)) {
467 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
470 if (const MemIntrinsic
*MI
= dyn_cast
<MemIntrinsic
>(I
)) {
471 auto AccessRange
= getMemIntrinsicAccessRange(MI
, UI
, Ptr
);
473 if (const auto *MTI
= dyn_cast
<MemTransferInst
>(MI
)) {
474 if (MTI
->getRawSource() != UI
&& MTI
->getRawDest() != UI
)
476 } else if (MI
->getRawDest() != UI
) {
479 Safe
= Safe
|| isSafeAccess(UI
, AI
, MI
->getLength());
480 US
.addRange(I
, AccessRange
, Safe
);
484 const auto &CB
= cast
<CallBase
>(*I
);
485 if (CB
.getReturnedArgOperand() == V
) {
486 if (Visited
.insert(I
).second
)
487 WorkList
.push_back(cast
<const Instruction
>(I
));
490 if (!CB
.isArgOperand(&UI
)) {
491 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
495 unsigned ArgNo
= CB
.getArgOperandNo(&UI
);
496 if (CB
.isByValArgument(ArgNo
)) {
497 auto TypeSize
= DL
.getTypeStoreSize(CB
.getParamByValType(ArgNo
));
498 auto AccessRange
= getAccessRange(UI
, Ptr
, TypeSize
);
499 bool Safe
= isSafeAccess(UI
, AI
, TypeSize
);
500 US
.addRange(I
, AccessRange
, Safe
);
504 // FIXME: consult devirt?
505 // Do not follow aliases, otherwise we could inadvertently follow
506 // dso_preemptable aliases or aliases with interposable linkage.
507 const GlobalValue
*Callee
=
508 dyn_cast
<GlobalValue
>(CB
.getCalledOperand()->stripPointerCasts());
510 US
.addRange(I
, UnknownRange
, /*IsSafe=*/false);
514 assert(isa
<Function
>(Callee
) || isa
<GlobalAlias
>(Callee
));
515 ConstantRange Offsets
= offsetFrom(UI
, Ptr
);
517 US
.Calls
.emplace(CallInfo
<GlobalValue
>(Callee
, ArgNo
), Offsets
);
519 Insert
.first
->second
= Insert
.first
->second
.unionWith(Offsets
);
524 if (Visited
.insert(I
).second
)
525 WorkList
.push_back(cast
<const Instruction
>(I
));
531 FunctionInfo
<GlobalValue
> StackSafetyLocalAnalysis::run() {
532 FunctionInfo
<GlobalValue
> Info
;
533 assert(!F
.isDeclaration() &&
534 "Can't run StackSafety on a function declaration");
536 LLVM_DEBUG(dbgs() << "[StackSafety] " << F
.getName() << "\n");
538 SmallVector
<AllocaInst
*, 64> Allocas
;
539 for (auto &I
: instructions(F
))
540 if (auto *AI
= dyn_cast
<AllocaInst
>(&I
))
541 Allocas
.push_back(AI
);
542 StackLifetime
SL(F
, Allocas
, StackLifetime::LivenessType::Must
);
545 for (auto *AI
: Allocas
) {
546 auto &UI
= Info
.Allocas
.emplace(AI
, PointerSize
).first
->second
;
547 analyzeAllUses(AI
, UI
, SL
);
550 for (Argument
&A
: F
.args()) {
551 // Non pointers and bypass arguments are not going to be used in any global
553 if (A
.getType()->isPointerTy() && !A
.hasByValAttr()) {
554 auto &UI
= Info
.Params
.emplace(A
.getArgNo(), PointerSize
).first
->second
;
555 analyzeAllUses(&A
, UI
, SL
);
559 LLVM_DEBUG(Info
.print(dbgs(), F
.getName(), &F
));
560 LLVM_DEBUG(dbgs() << "\n[StackSafety] done\n");
564 template <typename CalleeTy
> class StackSafetyDataFlowAnalysis
{
565 using FunctionMap
= std::map
<const CalleeTy
*, FunctionInfo
<CalleeTy
>>;
567 FunctionMap Functions
;
568 const ConstantRange UnknownRange
;
570 // Callee-to-Caller multimap.
571 DenseMap
<const CalleeTy
*, SmallVector
<const CalleeTy
*, 4>> Callers
;
572 SetVector
<const CalleeTy
*> WorkList
;
574 bool updateOneUse(UseInfo
<CalleeTy
> &US
, bool UpdateToFullSet
);
575 void updateOneNode(const CalleeTy
*Callee
, FunctionInfo
<CalleeTy
> &FS
);
576 void updateOneNode(const CalleeTy
*Callee
) {
577 updateOneNode(Callee
, Functions
.find(Callee
)->second
);
579 void updateAllNodes() {
580 for (auto &F
: Functions
)
581 updateOneNode(F
.first
, F
.second
);
585 void verifyFixedPoint();
589 StackSafetyDataFlowAnalysis(uint32_t PointerBitWidth
, FunctionMap Functions
)
590 : Functions(std::move(Functions
)),
591 UnknownRange(ConstantRange::getFull(PointerBitWidth
)) {}
593 const FunctionMap
&run();
595 ConstantRange
getArgumentAccessRange(const CalleeTy
*Callee
, unsigned ParamNo
,
596 const ConstantRange
&Offsets
) const;
599 template <typename CalleeTy
>
600 ConstantRange StackSafetyDataFlowAnalysis
<CalleeTy
>::getArgumentAccessRange(
601 const CalleeTy
*Callee
, unsigned ParamNo
,
602 const ConstantRange
&Offsets
) const {
603 auto FnIt
= Functions
.find(Callee
);
604 // Unknown callee (outside of LTO domain or an indirect call).
605 if (FnIt
== Functions
.end())
607 auto &FS
= FnIt
->second
;
608 auto ParamIt
= FS
.Params
.find(ParamNo
);
609 if (ParamIt
== FS
.Params
.end())
611 auto &Access
= ParamIt
->second
.Range
;
612 if (Access
.isEmptySet())
614 if (Access
.isFullSet())
616 return addOverflowNever(Access
, Offsets
);
619 template <typename CalleeTy
>
620 bool StackSafetyDataFlowAnalysis
<CalleeTy
>::updateOneUse(UseInfo
<CalleeTy
> &US
,
621 bool UpdateToFullSet
) {
622 bool Changed
= false;
623 for (auto &KV
: US
.Calls
) {
624 assert(!KV
.second
.isEmptySet() &&
625 "Param range can't be empty-set, invalid offset range");
627 ConstantRange CalleeRange
=
628 getArgumentAccessRange(KV
.first
.Callee
, KV
.first
.ParamNo
, KV
.second
);
629 if (!US
.Range
.contains(CalleeRange
)) {
632 US
.Range
= UnknownRange
;
634 US
.updateRange(CalleeRange
);
640 template <typename CalleeTy
>
641 void StackSafetyDataFlowAnalysis
<CalleeTy
>::updateOneNode(
642 const CalleeTy
*Callee
, FunctionInfo
<CalleeTy
> &FS
) {
643 bool UpdateToFullSet
= FS
.UpdateCount
> StackSafetyMaxIterations
;
644 bool Changed
= false;
645 for (auto &KV
: FS
.Params
)
646 Changed
|= updateOneUse(KV
.second
, UpdateToFullSet
);
649 LLVM_DEBUG(dbgs() << "=== update [" << FS
.UpdateCount
650 << (UpdateToFullSet
? ", full-set" : "") << "] " << &FS
652 // Callers of this function may need updating.
653 for (auto &CallerID
: Callers
[Callee
])
654 WorkList
.insert(CallerID
);
660 template <typename CalleeTy
>
661 void StackSafetyDataFlowAnalysis
<CalleeTy
>::runDataFlow() {
662 SmallVector
<const CalleeTy
*, 16> Callees
;
663 for (auto &F
: Functions
) {
666 for (auto &KV
: FS
.Params
)
667 for (auto &CS
: KV
.second
.Calls
)
668 Callees
.push_back(CS
.first
.Callee
);
671 Callees
.erase(std::unique(Callees
.begin(), Callees
.end()), Callees
.end());
673 for (auto &Callee
: Callees
)
674 Callers
[Callee
].push_back(F
.first
);
679 while (!WorkList
.empty()) {
680 const CalleeTy
*Callee
= WorkList
.pop_back_val();
681 updateOneNode(Callee
);
686 template <typename CalleeTy
>
687 void StackSafetyDataFlowAnalysis
<CalleeTy
>::verifyFixedPoint() {
690 assert(WorkList
.empty());
694 template <typename CalleeTy
>
695 const typename StackSafetyDataFlowAnalysis
<CalleeTy
>::FunctionMap
&
696 StackSafetyDataFlowAnalysis
<CalleeTy
>::run() {
698 LLVM_DEBUG(verifyFixedPoint());
702 FunctionSummary
*findCalleeFunctionSummary(ValueInfo VI
, StringRef ModuleId
) {
705 auto SummaryList
= VI
.getSummaryList();
706 GlobalValueSummary
* S
= nullptr;
707 for (const auto& GVS
: SummaryList
) {
710 if (const AliasSummary
*AS
= dyn_cast
<AliasSummary
>(GVS
.get()))
711 if (!AS
->hasAliasee())
713 if (!isa
<FunctionSummary
>(GVS
->getBaseObject()))
715 if (GlobalValue::isLocalLinkage(GVS
->linkage())) {
716 if (GVS
->modulePath() == ModuleId
) {
720 } else if (GlobalValue::isExternalLinkage(GVS
->linkage())) {
722 ++NumIndexCalleeMultipleExternal
;
726 } else if (GlobalValue::isWeakLinkage(GVS
->linkage())) {
728 ++NumIndexCalleeMultipleWeak
;
732 } else if (GlobalValue::isAvailableExternallyLinkage(GVS
->linkage()) ||
733 GlobalValue::isLinkOnceLinkage(GVS
->linkage())) {
734 if (SummaryList
.size() == 1)
736 // According thinLTOResolvePrevailingGUID these are unlikely prevailing.
738 ++NumIndexCalleeUnhandled
;
742 if (!S
->isLive() || !S
->isDSOLocal())
744 if (FunctionSummary
*FS
= dyn_cast
<FunctionSummary
>(S
))
746 AliasSummary
*AS
= dyn_cast
<AliasSummary
>(S
);
747 if (!AS
|| !AS
->hasAliasee())
749 S
= AS
->getBaseObject();
756 const Function
*findCalleeInModule(const GlobalValue
*GV
) {
758 if (GV
->isDeclaration() || GV
->isInterposable() || !GV
->isDSOLocal())
760 if (const Function
*F
= dyn_cast
<Function
>(GV
))
762 const GlobalAlias
*A
= dyn_cast
<GlobalAlias
>(GV
);
765 GV
= A
->getAliaseeObject();
772 const ConstantRange
*findParamAccess(const FunctionSummary
&FS
,
775 assert(FS
.isDSOLocal());
776 for (const auto &PS
: FS
.paramAccesses())
777 if (ParamNo
== PS
.ParamNo
)
782 void resolveAllCalls(UseInfo
<GlobalValue
> &Use
,
783 const ModuleSummaryIndex
*Index
) {
784 ConstantRange
FullSet(Use
.Range
.getBitWidth(), true);
785 // Move Use.Calls to a temp storage and repopulate - don't use std::move as it
786 // leaves Use.Calls in an undefined state.
787 UseInfo
<GlobalValue
>::CallsTy TmpCalls
;
788 std::swap(TmpCalls
, Use
.Calls
);
789 for (const auto &C
: TmpCalls
) {
790 const Function
*F
= findCalleeInModule(C
.first
.Callee
);
792 Use
.Calls
.emplace(CallInfo
<GlobalValue
>(F
, C
.first
.ParamNo
), C
.second
);
797 return Use
.updateRange(FullSet
);
798 FunctionSummary
*FS
=
799 findCalleeFunctionSummary(Index
->getValueInfo(C
.first
.Callee
->getGUID()),
800 C
.first
.Callee
->getParent()->getModuleIdentifier());
801 ++NumModuleCalleeLookupTotal
;
803 ++NumModuleCalleeLookupFailed
;
804 return Use
.updateRange(FullSet
);
806 const ConstantRange
*Found
= findParamAccess(*FS
, C
.first
.ParamNo
);
807 if (!Found
|| Found
->isFullSet())
808 return Use
.updateRange(FullSet
);
809 ConstantRange Access
= Found
->sextOrTrunc(Use
.Range
.getBitWidth());
810 if (!Access
.isEmptySet())
811 Use
.updateRange(addOverflowNever(Access
, C
.second
));
815 GVToSSI
createGlobalStackSafetyInfo(
816 std::map
<const GlobalValue
*, FunctionInfo
<GlobalValue
>> Functions
,
817 const ModuleSummaryIndex
*Index
) {
819 if (Functions
.empty())
822 // FIXME: Simplify printing and remove copying here.
823 auto Copy
= Functions
;
825 for (auto &FnKV
: Copy
)
826 for (auto &KV
: FnKV
.second
.Params
) {
827 resolveAllCalls(KV
.second
, Index
);
828 if (KV
.second
.Range
.isFullSet())
829 KV
.second
.Calls
.clear();
832 uint32_t PointerSize
=
833 Copy
.begin()->first
->getParent()->getDataLayout().getPointerSizeInBits();
834 StackSafetyDataFlowAnalysis
<GlobalValue
> SSDFA(PointerSize
, std::move(Copy
));
836 for (const auto &F
: SSDFA
.run()) {
838 auto &SrcF
= Functions
[F
.first
];
839 for (auto &KV
: FI
.Allocas
) {
841 resolveAllCalls(A
, Index
);
842 for (auto &C
: A
.Calls
) {
843 A
.updateRange(SSDFA
.getArgumentAccessRange(C
.first
.Callee
,
844 C
.first
.ParamNo
, C
.second
));
846 // FIXME: This is needed only to preserve calls in print() results.
847 A
.Calls
= SrcF
.Allocas
.find(KV
.first
)->second
.Calls
;
849 for (auto &KV
: FI
.Params
) {
851 P
.Calls
= SrcF
.Params
.find(KV
.first
)->second
.Calls
;
853 SSI
[F
.first
] = std::move(FI
);
859 } // end anonymous namespace
861 StackSafetyInfo::StackSafetyInfo() = default;
863 StackSafetyInfo::StackSafetyInfo(Function
*F
,
864 std::function
<ScalarEvolution
&()> GetSE
)
865 : F(F
), GetSE(GetSE
) {}
867 StackSafetyInfo::StackSafetyInfo(StackSafetyInfo
&&) = default;
869 StackSafetyInfo
&StackSafetyInfo::operator=(StackSafetyInfo
&&) = default;
871 StackSafetyInfo::~StackSafetyInfo() = default;
873 const StackSafetyInfo::InfoTy
&StackSafetyInfo::getInfo() const {
875 StackSafetyLocalAnalysis
SSLA(*F
, GetSE());
876 Info
.reset(new InfoTy
{SSLA
.run()});
881 void StackSafetyInfo::print(raw_ostream
&O
) const {
882 getInfo().Info
.print(O
, F
->getName(), dyn_cast
<Function
>(F
));
886 const StackSafetyGlobalInfo::InfoTy
&StackSafetyGlobalInfo::getInfo() const {
888 std::map
<const GlobalValue
*, FunctionInfo
<GlobalValue
>> Functions
;
889 for (auto &F
: M
->functions()) {
890 if (!F
.isDeclaration()) {
891 auto FI
= GetSSI(F
).getInfo().Info
;
892 Functions
.emplace(&F
, std::move(FI
));
895 Info
.reset(new InfoTy
{
896 createGlobalStackSafetyInfo(std::move(Functions
), Index
), {}, {}});
898 for (auto &FnKV
: Info
->Info
) {
899 for (auto &KV
: FnKV
.second
.Allocas
) {
901 const AllocaInst
*AI
= KV
.first
;
902 auto AIRange
= getStaticAllocaSizeRange(*AI
);
903 if (AIRange
.contains(KV
.second
.Range
)) {
904 Info
->SafeAllocas
.insert(AI
);
905 ++NumAllocaStackSafe
;
907 Info
->UnsafeAccesses
.insert(KV
.second
.UnsafeAccesses
.begin(),
908 KV
.second
.UnsafeAccesses
.end());
912 if (StackSafetyPrint
)
918 std::vector
<FunctionSummary::ParamAccess
>
919 StackSafetyInfo::getParamAccesses(ModuleSummaryIndex
&Index
) const {
920 // Implementation transforms internal representation of parameter information
921 // into FunctionSummary format.
922 std::vector
<FunctionSummary::ParamAccess
> ParamAccesses
;
923 for (const auto &KV
: getInfo().Info
.Params
) {
924 auto &PS
= KV
.second
;
925 // Parameter accessed by any or unknown offset, represented as FullSet by
926 // StackSafety, is handled as the parameter for which we have no
927 // StackSafety info at all. So drop it to reduce summary size.
928 if (PS
.Range
.isFullSet())
931 ParamAccesses
.emplace_back(KV
.first
, PS
.Range
);
932 FunctionSummary::ParamAccess
&Param
= ParamAccesses
.back();
934 Param
.Calls
.reserve(PS
.Calls
.size());
935 for (const auto &C
: PS
.Calls
) {
936 // Parameter forwarded into another function by any or unknown offset
937 // will make ParamAccess::Range as FullSet anyway. So we can drop the
938 // entire parameter like we did above.
939 // TODO(vitalybuka): Return already filtered parameters from getInfo().
940 if (C
.second
.isFullSet()) {
941 ParamAccesses
.pop_back();
944 Param
.Calls
.emplace_back(C
.first
.ParamNo
,
945 Index
.getOrInsertValueInfo(C
.first
.Callee
),
949 for (FunctionSummary::ParamAccess
&Param
: ParamAccesses
) {
950 sort(Param
.Calls
, [](const FunctionSummary::ParamAccess::Call
&L
,
951 const FunctionSummary::ParamAccess::Call
&R
) {
952 return std::tie(L
.ParamNo
, L
.Callee
) < std::tie(R
.ParamNo
, R
.Callee
);
955 return ParamAccesses
;
958 StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default;
960 StackSafetyGlobalInfo::StackSafetyGlobalInfo(
961 Module
*M
, std::function
<const StackSafetyInfo
&(Function
&F
)> GetSSI
,
962 const ModuleSummaryIndex
*Index
)
963 : M(M
), GetSSI(GetSSI
), Index(Index
) {
968 StackSafetyGlobalInfo::StackSafetyGlobalInfo(StackSafetyGlobalInfo
&&) =
971 StackSafetyGlobalInfo
&
972 StackSafetyGlobalInfo::operator=(StackSafetyGlobalInfo
&&) = default;
974 StackSafetyGlobalInfo::~StackSafetyGlobalInfo() = default;
976 bool StackSafetyGlobalInfo::isSafe(const AllocaInst
&AI
) const {
977 const auto &Info
= getInfo();
978 return Info
.SafeAllocas
.count(&AI
);
981 bool StackSafetyGlobalInfo::stackAccessIsSafe(const Instruction
&I
) const {
982 const auto &Info
= getInfo();
983 return Info
.UnsafeAccesses
.find(&I
) == Info
.UnsafeAccesses
.end();
986 void StackSafetyGlobalInfo::print(raw_ostream
&O
) const {
987 auto &SSI
= getInfo().Info
;
990 const Module
&M
= *SSI
.begin()->first
->getParent();
991 for (const auto &F
: M
.functions()) {
992 if (!F
.isDeclaration()) {
993 SSI
.find(&F
)->second
.print(O
, F
.getName(), &F
);
994 O
<< " safe accesses:"
996 for (const auto &I
: instructions(F
)) {
997 const CallInst
*Call
= dyn_cast
<CallInst
>(&I
);
998 if ((isa
<StoreInst
>(I
) || isa
<LoadInst
>(I
) || isa
<MemIntrinsic
>(I
) ||
999 isa
<AtomicCmpXchgInst
>(I
) || isa
<AtomicRMWInst
>(I
) ||
1000 (Call
&& Call
->hasByValArgument())) &&
1001 stackAccessIsSafe(I
)) {
1002 O
<< " " << I
<< "\n";
1010 LLVM_DUMP_METHOD
void StackSafetyGlobalInfo::dump() const { print(dbgs()); }
1012 AnalysisKey
StackSafetyAnalysis::Key
;
1014 StackSafetyInfo
StackSafetyAnalysis::run(Function
&F
,
1015 FunctionAnalysisManager
&AM
) {
1016 return StackSafetyInfo(&F
, [&AM
, &F
]() -> ScalarEvolution
& {
1017 return AM
.getResult
<ScalarEvolutionAnalysis
>(F
);
1021 PreservedAnalyses
StackSafetyPrinterPass::run(Function
&F
,
1022 FunctionAnalysisManager
&AM
) {
1023 OS
<< "'Stack Safety Local Analysis' for function '" << F
.getName() << "'\n";
1024 AM
.getResult
<StackSafetyAnalysis
>(F
).print(OS
);
1025 return PreservedAnalyses::all();
1028 char StackSafetyInfoWrapperPass::ID
= 0;
1030 StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID
) {
1031 initializeStackSafetyInfoWrapperPassPass(*PassRegistry::getPassRegistry());
1034 void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
1035 AU
.addRequiredTransitive
<ScalarEvolutionWrapperPass
>();
1036 AU
.setPreservesAll();
1039 void StackSafetyInfoWrapperPass::print(raw_ostream
&O
, const Module
*M
) const {
1043 bool StackSafetyInfoWrapperPass::runOnFunction(Function
&F
) {
1044 auto *SE
= &getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
1045 SSI
= {&F
, [SE
]() -> ScalarEvolution
& { return *SE
; }};
1049 AnalysisKey
StackSafetyGlobalAnalysis::Key
;
1051 StackSafetyGlobalInfo
1052 StackSafetyGlobalAnalysis::run(Module
&M
, ModuleAnalysisManager
&AM
) {
1053 // FIXME: Lookup Module Summary.
1054 FunctionAnalysisManager
&FAM
=
1055 AM
.getResult
<FunctionAnalysisManagerModuleProxy
>(M
).getManager();
1057 [&FAM
](Function
&F
) -> const StackSafetyInfo
& {
1058 return FAM
.getResult
<StackSafetyAnalysis
>(F
);
1063 PreservedAnalyses
StackSafetyGlobalPrinterPass::run(Module
&M
,
1064 ModuleAnalysisManager
&AM
) {
1065 OS
<< "'Stack Safety Analysis' for module '" << M
.getName() << "'\n";
1066 AM
.getResult
<StackSafetyGlobalAnalysis
>(M
).print(OS
);
1067 return PreservedAnalyses::all();
1070 char StackSafetyGlobalInfoWrapperPass::ID
= 0;
1072 StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass()
1074 initializeStackSafetyGlobalInfoWrapperPassPass(
1075 *PassRegistry::getPassRegistry());
1078 StackSafetyGlobalInfoWrapperPass::~StackSafetyGlobalInfoWrapperPass() = default;
1080 void StackSafetyGlobalInfoWrapperPass::print(raw_ostream
&O
,
1081 const Module
*M
) const {
1085 void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage(
1086 AnalysisUsage
&AU
) const {
1087 AU
.setPreservesAll();
1088 AU
.addRequired
<StackSafetyInfoWrapperPass
>();
1091 bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module
&M
) {
1092 const ModuleSummaryIndex
*ImportSummary
= nullptr;
1093 if (auto *IndexWrapperPass
=
1094 getAnalysisIfAvailable
<ImmutableModuleSummaryIndexWrapperPass
>())
1095 ImportSummary
= IndexWrapperPass
->getIndex();
1098 [this](Function
&F
) -> const StackSafetyInfo
& {
1099 return getAnalysis
<StackSafetyInfoWrapperPass
>(F
).getResult();
1105 bool llvm::needsParamAccessSummary(const Module
&M
) {
1108 for (const auto &F
: M
.functions())
1109 if (F
.hasFnAttribute(Attribute::SanitizeMemTag
))
1114 void llvm::generateParamAccessSummary(ModuleSummaryIndex
&Index
) {
1115 if (!Index
.hasParamAccess())
1117 const ConstantRange
FullSet(FunctionSummary::ParamAccess::RangeWidth
, true);
1119 auto CountParamAccesses
= [&](auto &Stat
) {
1120 if (!AreStatisticsEnabled())
1122 for (auto &GVS
: Index
)
1123 for (auto &GV
: GVS
.second
.SummaryList
)
1124 if (FunctionSummary
*FS
= dyn_cast
<FunctionSummary
>(GV
.get()))
1125 Stat
+= FS
->paramAccesses().size();
1128 CountParamAccesses(NumCombinedParamAccessesBefore
);
1130 std::map
<const FunctionSummary
*, FunctionInfo
<FunctionSummary
>> Functions
;
1132 // Convert the ModuleSummaryIndex to a FunctionMap
1133 for (auto &GVS
: Index
) {
1134 for (auto &GV
: GVS
.second
.SummaryList
) {
1135 FunctionSummary
*FS
= dyn_cast
<FunctionSummary
>(GV
.get());
1136 if (!FS
|| FS
->paramAccesses().empty())
1138 if (FS
->isLive() && FS
->isDSOLocal()) {
1139 FunctionInfo
<FunctionSummary
> FI
;
1140 for (const auto &PS
: FS
->paramAccesses()) {
1143 .emplace(PS
.ParamNo
, FunctionSummary::ParamAccess::RangeWidth
)
1146 for (const auto &Call
: PS
.Calls
) {
1147 assert(!Call
.Offsets
.isFullSet());
1148 FunctionSummary
*S
=
1149 findCalleeFunctionSummary(Call
.Callee
, FS
->modulePath());
1150 ++NumCombinedCalleeLookupTotal
;
1152 ++NumCombinedCalleeLookupFailed
;
1157 US
.Calls
.emplace(CallInfo
<FunctionSummary
>(S
, Call
.ParamNo
),
1161 Functions
.emplace(FS
, std::move(FI
));
1163 // Reset data for all summaries. Alive and DSO local will be set back from
1164 // of data flow results below. Anything else will not be accessed
1165 // by ThinLTO backend, so we can save on bitcode size.
1166 FS
->setParamAccesses({});
1169 NumCombinedDataFlowNodes
+= Functions
.size();
1170 StackSafetyDataFlowAnalysis
<FunctionSummary
> SSDFA(
1171 FunctionSummary::ParamAccess::RangeWidth
, std::move(Functions
));
1172 for (const auto &KV
: SSDFA
.run()) {
1173 std::vector
<FunctionSummary::ParamAccess
> NewParams
;
1174 NewParams
.reserve(KV
.second
.Params
.size());
1175 for (const auto &Param
: KV
.second
.Params
) {
1176 // It's not needed as FullSet is processed the same as a missing value.
1177 if (Param
.second
.Range
.isFullSet())
1179 NewParams
.emplace_back();
1180 FunctionSummary::ParamAccess
&New
= NewParams
.back();
1181 New
.ParamNo
= Param
.first
;
1182 New
.Use
= Param
.second
.Range
; // Only range is needed.
1184 const_cast<FunctionSummary
*>(KV
.first
)->setParamAccesses(
1185 std::move(NewParams
));
1188 CountParamAccesses(NumCombinedParamAccessesAfter
);
1191 static const char LocalPassArg
[] = "stack-safety-local";
1192 static const char LocalPassName
[] = "Stack Safety Local Analysis";
1193 INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass
, LocalPassArg
, LocalPassName
,
1195 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass
)
1196 INITIALIZE_PASS_END(StackSafetyInfoWrapperPass
, LocalPassArg
, LocalPassName
,
1199 static const char GlobalPassName
[] = "Stack Safety Analysis";
1200 INITIALIZE_PASS_BEGIN(StackSafetyGlobalInfoWrapperPass
, DEBUG_TYPE
,
1201 GlobalPassName
, false, true)
1202 INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass
)
1203 INITIALIZE_PASS_DEPENDENCY(ImmutableModuleSummaryIndexWrapperPass
)
1204 INITIALIZE_PASS_END(StackSafetyGlobalInfoWrapperPass
, DEBUG_TYPE
,
1205 GlobalPassName
, false, true)