LLVM 22.0.0git
MemoryTaggingSupport.cpp
Go to the documentation of this file.
1//== MemoryTaggingSupport.cpp - helpers for memory tagging implementations ===//
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7//
8// This file declares common infrastructure for HWAddressSanitizer and
9// Aarch64StackTagging.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/Analysis/CFG.h"
21#include "llvm/IR/BasicBlock.h"
22#include "llvm/IR/IRBuilder.h"
26
27namespace llvm {
28namespace memtag {
29namespace {
30bool maybeReachableFromEachOther(const SmallVectorImpl<IntrinsicInst *> &Insts,
31 const DominatorTree *DT, const LoopInfo *LI,
32 size_t MaxLifetimes) {
33 // If we have too many lifetime ends, give up, as the algorithm below is N^2.
34 if (Insts.size() > MaxLifetimes)
35 return true;
36 for (size_t I = 0; I < Insts.size(); ++I) {
37 for (size_t J = 0; J < Insts.size(); ++J) {
38 if (I == J)
39 continue;
40 if (isPotentiallyReachable(Insts[I], Insts[J], nullptr, DT, LI))
41 return true;
42 }
43 }
44 return false;
45}
46} // namespace
47
49 const LoopInfo &LI, const Instruction *Start,
52 llvm::function_ref<void(Instruction *)> Callback) {
53 if (Ends.size() == 1 && PDT.dominates(Ends[0], Start)) {
54 Callback(Ends[0]);
55 return true;
56 }
58 for (auto *End : Ends) {
59 EndBlocks.insert(End->getParent());
60 }
61 SmallVector<Instruction *, 8> ReachableRetVec;
62 unsigned NumCoveredExits = 0;
63 for (auto *RI : RetVec) {
64 if (!isPotentiallyReachable(Start, RI, nullptr, &DT, &LI))
65 continue;
66 ReachableRetVec.push_back(RI);
67 // If there is an end in the same basic block as the return, we know for
68 // sure that the return is covered. Otherwise, we can check whether there
69 // is a way to reach the RI from the start of the lifetime without passing
70 // through an end.
71 if (EndBlocks.contains(RI->getParent()) ||
72 !isPotentiallyReachable(Start, RI, &EndBlocks, &DT, &LI)) {
73 ++NumCoveredExits;
74 }
75 }
76 if (NumCoveredExits == ReachableRetVec.size()) {
77 for_each(Ends, Callback);
78 } else {
79 // If there's a mix of covered and non-covered exits, just put the untag
80 // on exits, so we avoid the redundancy of untagging twice.
81 for_each(ReachableRetVec, Callback);
82 // We may have inserted untag outside of the lifetime interval.
83 // Signal the caller to remove the lifetime end call for this alloca.
84 return false;
85 }
86 return true;
87}
88
90 const SmallVectorImpl<IntrinsicInst *> &LifetimeEnd,
91 const DominatorTree *DT, const LoopInfo *LI,
92 size_t MaxLifetimes) {
93 // An alloca that has exactly one start and end in every possible execution.
94 // If it has multiple ends, they have to be unreachable from each other, so
95 // at most one of them is actually used for each execution of the function.
96 return LifetimeStart.size() == 1 &&
97 (LifetimeEnd.size() == 1 ||
98 (LifetimeEnd.size() > 0 &&
99 !maybeReachableFromEachOther(LifetimeEnd, DT, LI, MaxLifetimes)));
100}
101
103 if (isa<ReturnInst>(Inst)) {
104 if (CallInst *CI = Inst.getParent()->getTerminatingMustTailCall())
105 return CI;
106 return &Inst;
107 }
109 return &Inst;
110 }
111 return nullptr;
112}
113
115 Instruction &Inst) {
116 // Visit non-intrinsic debug-info records attached to Inst.
118 auto AddIfInteresting = [&](Value *V) {
119 if (auto *AI = dyn_cast_or_null<AllocaInst>(V)) {
120 if (getAllocaInterestingness(*AI) !=
122 return;
123 AllocaInfo &AInfo = Info.AllocasToInstrument[AI];
124 auto &DVRVec = AInfo.DbgVariableRecords;
125 if (DVRVec.empty() || DVRVec.back() != &DVR)
126 DVRVec.push_back(&DVR);
127 }
128 };
129
130 for_each(DVR.location_ops(), AddIfInteresting);
131 if (DVR.isDbgAssign())
132 AddIfInteresting(DVR.getAddress());
133 }
134
135 if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
136 if (CI->canReturnTwice()) {
137 Info.CallsReturnTwice = true;
138 }
139 }
140 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
141 switch (getAllocaInterestingness(*AI)) {
143 Info.AllocasToInstrument[AI].AI = AI;
144 ORE.emit([&]() {
145 return OptimizationRemarkMissed(DebugType, "safeAlloca", &Inst);
146 });
147 break;
149 ORE.emit(
150 [&]() { return OptimizationRemark(DebugType, "safeAlloca", &Inst); });
151 break;
153 break;
154 }
155 return;
156 }
157 if (auto *II = dyn_cast<LifetimeIntrinsic>(&Inst)) {
158 AllocaInst *AI = dyn_cast<AllocaInst>(II->getArgOperand(0));
159 if (!AI ||
161 return;
162 if (II->getIntrinsicID() == Intrinsic::lifetime_start)
163 Info.AllocasToInstrument[AI].LifetimeStart.push_back(II);
164 else
165 Info.AllocasToInstrument[AI].LifetimeEnd.push_back(II);
166 return;
167 }
168
170 if (ExitUntag)
171 Info.RetVec.push_back(ExitUntag);
172}
173
176 if (AI.getAllocatedType()->isSized() &&
177 // FIXME: support vscale.
179 // FIXME: instrument dynamic allocas, too
180 AI.isStaticAlloca() &&
181 // alloca() may be called with 0 size, ignore it.
183 // We are only interested in allocas not promotable to registers.
184 // Promotable allocas are common under -O0.
185 !isAllocaPromotable(&AI) &&
186 // inalloca allocas are not treated as static, and we don't want
187 // dynamic alloca instrumentation for them as well.
188 !AI.isUsedWithInAlloca() &&
189 // swifterror allocas are register promoted by ISel
190 !AI.isSwiftError()) {
191 if (!(SSI && SSI->isSafe(AI))) {
193 }
194 // safe allocas are not interesting
196 }
198}
199
201 auto DL = AI.getDataLayout();
202 return *AI.getAllocationSize(DL);
203}
204
206 const Align NewAlignment = std::max(Info.AI->getAlign(), Alignment);
207 Info.AI->setAlignment(NewAlignment);
208 auto &Ctx = Info.AI->getFunction()->getContext();
209
211 uint64_t AlignedSize = alignTo(Size, Alignment);
212 if (Size == AlignedSize)
213 return;
214
215 // Add padding to the alloca.
216 Type *AllocatedType =
217 Info.AI->isArrayAllocation()
219 Info.AI->getAllocatedType(),
220 cast<ConstantInt>(Info.AI->getArraySize())->getZExtValue())
221 : Info.AI->getAllocatedType();
222 Type *PaddingType = ArrayType::get(Type::getInt8Ty(Ctx), AlignedSize - Size);
223 Type *TypeWithPadding = StructType::get(AllocatedType, PaddingType);
224 auto *NewAI = new AllocaInst(TypeWithPadding, Info.AI->getAddressSpace(),
225 nullptr, "", Info.AI->getIterator());
226 NewAI->takeName(Info.AI);
227 NewAI->setAlignment(Info.AI->getAlign());
228 NewAI->setUsedWithInAlloca(Info.AI->isUsedWithInAlloca());
229 NewAI->setSwiftError(Info.AI->isSwiftError());
230 NewAI->copyMetadata(*Info.AI);
231
232 Info.AI->replaceAllUsesWith(NewAI);
233 Info.AI->eraseFromParent();
234 Info.AI = NewAI;
235}
236
238 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
239 MDNode *MD =
240 MDNode::get(M->getContext(), {MDString::get(M->getContext(), Name)});
241 Value *Args[] = {MetadataAsValue::get(M->getContext(), MD)};
242 return IRB.CreateIntrinsic(Intrinsic::read_register,
243 IRB.getIntPtrTy(M->getDataLayout()), Args);
244}
245
246Value *getPC(const Triple &TargetTriple, IRBuilder<> &IRB) {
247 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
248 if (TargetTriple.getArch() == Triple::aarch64)
249 return memtag::readRegister(IRB, "pc");
250 return IRB.CreatePtrToInt(IRB.GetInsertBlock()->getParent(),
251 IRB.getIntPtrTy(M->getDataLayout()));
252}
253
256 Module *M = F->getParent();
257 return IRB.CreatePtrToInt(
258 IRB.CreateIntrinsic(Intrinsic::frameaddress,
259 IRB.getPtrTy(M->getDataLayout().getAllocaAddrSpace()),
260 {Constant::getNullValue(IRB.getInt32Ty())}),
261 IRB.getIntPtrTy(M->getDataLayout()));
262}
263
265 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
266 // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
267 // in Bionic's libc/private/bionic_tls.h.
268 Function *ThreadPointerFunc = Intrinsic::getOrInsertDeclaration(
269 M, Intrinsic::thread_pointer,
270 IRB.getPtrTy(M->getDataLayout().getDefaultGlobalsAddressSpace()));
271 return IRB.CreateConstGEP1_32(IRB.getInt8Ty(),
272 IRB.CreateCall(ThreadPointerFunc), 8 * Slot);
273}
274
276 return DVR->isDbgAssign() ? DVR : nullptr;
277}
278
280 auto AnnotateDbgRecord = [&](DbgVariableRecord *DPtr) {
281 // Prepend "tag_offset, N" to the dwarf expression.
282 // Tag offset logically applies to the alloca pointer, and it makes sense
283 // to put it at the beginning of the expression.
285 for (size_t LocNo = 0; LocNo < DPtr->getNumVariableLocationOps(); ++LocNo)
286 if (DPtr->getVariableLocationOp(LocNo) == Info.AI)
287 DPtr->setExpression(
288 DIExpression::appendOpsToArg(DPtr->getExpression(), NewOps, LocNo));
289 if (auto *DAI = DynCastToDbgAssign(DPtr)) {
290 if (DAI->getAddress() == Info.AI)
291 DAI->setAddressExpression(
292 DIExpression::prependOpcodes(DAI->getAddressExpression(), NewOps));
293 }
294 };
295
296 llvm::for_each(Info.DbgVariableRecords, AnnotateDbgRecord);
297}
298
300 unsigned int Inc) {
301 // Update the ring buffer. Top byte of ThreadLong defines the size of the
302 // buffer in pages, it must be a power of two, and the start of the buffer
303 // must be aligned by twice that much. Therefore wrap around of the ring
304 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
305 // The use of AShr instead of LShr is due to
306 // https://bugs.llvm.org/show_bug.cgi?id=39030
307 // Runtime library makes sure not to use the highest bit.
308 //
309 // Mechanical proof of this address calculation can be found at:
310 // https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/prove_hwasanwrap.smt2
311 //
312 // Example of the wrap case for N = 1
313 // Pointer: 0x01AAAAAAAAAAAFF8
314 // +
315 // 0x0000000000000008
316 // =
317 // 0x01AAAAAAAAAAB000
318 // &
319 // WrapMask: 0xFFFFFFFFFFFFF000
320 // =
321 // 0x01AAAAAAAAAAA000
322 //
323 // Then the WrapMask will be a no-op until the next wrap case.
324 assert((4096 % Inc) == 0);
325 Value *WrapMask = IRB.CreateXor(
326 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
327 ConstantInt::get(ThreadLong->getType(), (uint64_t)-1));
328 return IRB.CreateAnd(
329 IRB.CreateAdd(ThreadLong, ConstantInt::get(ThreadLong->getType(), Inc)),
330 WrapMask);
331}
332
333} // namespace memtag
334} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Analysis containing CSE Info
Definition CSEInfo.cpp:27
This file contains constants used for implementing Dwarf debug support.
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
uint64_t IntrinsicInst * II
This file contains some templates that are useful if you are working with the STL at all.
an instruction to allocate memory on the stack
bool isSwiftError() const
Return true if this alloca is used as a swifterror argument to a call.
LLVM_ABI bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size.
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
bool isUsedWithInAlloca() const
Return true if this alloca is used as an inalloca argument to a call.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI DIExpression * appendOpsToArg(const DIExpression *Expr, ArrayRef< uint64_t > Ops, unsigned ArgNo, bool StackValue=false)
Create a copy of Expr by appending the given list of Ops to each instance of the operand DW_OP_LLVM_a...
static LLVM_ABI DIExpression * prependOpcodes(const DIExpression *Expr, SmallVectorImpl< uint64_t > &Ops, bool StackValue=false, bool EntryValue=false)
Prepend DIExpr with the given opcodes and optionally turn it into a stack value.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:165
Module * getParent()
Get the module that this global value is contained inside of...
Value * CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
Definition IRBuilder.h:1936
IntegerType * getIntPtrTy(const DataLayout &DL, unsigned AddrSpace=0)
Fetch the type of an integer with size at least as big as that of a pointer in the given address spac...
Definition IRBuilder.h:611
BasicBlock * GetInsertBlock() const
Definition IRBuilder.h:201
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1492
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1551
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1403
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2194
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2508
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:605
Value * CreateAShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1532
Value * CreateXor(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1599
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Definition IRBuilder.h:552
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2780
iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange() const
Return a range over the DbgRecords attached to this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Metadata node.
Definition Metadata.h:1077
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1565
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:103
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
The optimization diagnostic interface.
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for missed-optimization remarks.
Diagnostic information for applied optimization remarks.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
LLVM_ABI bool dominates(const Instruction *I1, const Instruction *I2) const
Return true if I1 dominates I2.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:414
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition Triple.h:411
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
LLVM_ABI bool isScalableTy(SmallPtrSetImpl< const Type * > &Visited) const
Return true if this is a type whose size is a known multiple of vscale.
Definition Type.cpp:62
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:295
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
Definition Type.h:311
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
void visit(OptimizationRemarkEmitter &ORE, Instruction &Inst)
AllocaInterestingness getAllocaInterestingness(const AllocaInst &AI)
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
@ DW_OP_LLVM_tag_offset
Only used in LLVM metadata.
Definition Dwarf.h:145
Value * getFP(IRBuilder<> &IRB)
bool isStandardLifetime(const SmallVectorImpl< IntrinsicInst * > &LifetimeStart, const SmallVectorImpl< IntrinsicInst * > &LifetimeEnd, const DominatorTree *DT, const LoopInfo *LI, size_t MaxLifetimes)
bool forAllReachableExits(const DominatorTree &DT, const PostDominatorTree &PDT, const LoopInfo &LI, const Instruction *Start, const SmallVectorImpl< IntrinsicInst * > &Ends, const SmallVectorImpl< Instruction * > &RetVec, llvm::function_ref< void(Instruction *)> Callback)
uint64_t getAllocaSizeInBytes(const AllocaInst &AI)
Value * getAndroidSlotPtr(IRBuilder<> &IRB, int Slot)
static DbgVariableRecord * DynCastToDbgAssign(DbgVariableRecord *DVR)
Value * readRegister(IRBuilder<> &IRB, StringRef Name)
Value * incrementThreadLong(IRBuilder<> &IRB, Value *ThreadLong, unsigned int Inc)
void annotateDebugRecords(AllocaInfo &Info, unsigned int Tag)
Instruction * getUntagLocationIfFunctionExit(Instruction &Inst)
void alignAndPadAlloca(memtag::AllocaInfo &Info, llvm::Align Align)
Value * getPC(const Triple &TargetTriple, IRBuilder<> &IRB)
This is an optimization pass for GlobalISel generic memory operations.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1720
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
LLVM_ABI bool isAllocaPromotable(const AllocaInst *AI)
Return true if this alloca is legal for promotion.
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:759
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:548
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:155
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
LLVM_ABI bool isPotentiallyReachable(const Instruction *From, const Instruction *To, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet=nullptr, const DominatorTree *DT=nullptr, const LoopInfo *LI=nullptr)
Determine whether instruction 'To' is reachable from 'From', without passing through any blocks in Ex...
Definition CFG.cpp:282
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
SmallVector< DbgVariableRecord *, 2 > DbgVariableRecords