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
13 #include "llvm/Transforms/Utils/MemoryTaggingSupport.h"
14
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Analysis/CFG.h"
17 #include "llvm/Analysis/PostDominators.h"
18 #include "llvm/Analysis/StackSafetyAnalysis.h"
19 #include "llvm/Analysis/ValueTracking.h"
20 #include "llvm/BinaryFormat/Dwarf.h"
21 #include "llvm/IR/BasicBlock.h"
22 #include "llvm/IR/IRBuilder.h"
23 #include "llvm/IR/IntrinsicInst.h"
24 #include "llvm/TargetParser/Triple.h"
25 #include "llvm/Transforms/Utils/PromoteMemToReg.h"
26
27 namespace llvm {
28 namespace memtag {
29 namespace {
maybeReachableFromEachOther(const SmallVectorImpl<IntrinsicInst * > & Insts,const DominatorTree * DT,const LoopInfo * LI,size_t MaxLifetimes)30 bool 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
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)48 bool forAllReachableExits(const DominatorTree &DT, const PostDominatorTree &PDT,
49 const LoopInfo &LI, const Instruction *Start,
50 const SmallVectorImpl<IntrinsicInst *> &Ends,
51 const SmallVectorImpl<Instruction *> &RetVec,
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 }
57 SmallPtrSet<BasicBlock *, 2> EndBlocks;
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
isStandardLifetime(const SmallVectorImpl<IntrinsicInst * > & LifetimeStart,const SmallVectorImpl<IntrinsicInst * > & LifetimeEnd,const DominatorTree * DT,const LoopInfo * LI,size_t MaxLifetimes)89 bool isStandardLifetime(const SmallVectorImpl<IntrinsicInst *> &LifetimeStart,
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
getUntagLocationIfFunctionExit(Instruction & Inst)102 Instruction *getUntagLocationIfFunctionExit(Instruction &Inst) {
103 if (isa<ReturnInst>(Inst)) {
104 if (CallInst *CI = Inst.getParent()->getTerminatingMustTailCall())
105 return CI;
106 return &Inst;
107 }
108 if (isa<ResumeInst, CleanupReturnInst>(Inst)) {
109 return &Inst;
110 }
111 return nullptr;
112 }
113
visit(OptimizationRemarkEmitter & ORE,Instruction & Inst)114 void StackInfoBuilder::visit(OptimizationRemarkEmitter &ORE,
115 Instruction &Inst) {
116 // Visit non-intrinsic debug-info records attached to Inst.
117 for (DbgVariableRecord &DVR : filterDbgVars(Inst.getDbgRecordRange())) {
118 auto AddIfInteresting = [&](Value *V) {
119 if (auto *AI = dyn_cast_or_null<AllocaInst>(V)) {
120 if (getAllocaInterestingness(*AI) !=
121 AllocaInterestingness::kInteresting)
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)) {
142 case AllocaInterestingness::kInteresting:
143 Info.AllocasToInstrument[AI].AI = AI;
144 ORE.emit([&]() {
145 return OptimizationRemarkMissed(DebugType, "safeAlloca", &Inst);
146 });
147 break;
148 case AllocaInterestingness::kSafe:
149 ORE.emit(
150 [&]() { return OptimizationRemark(DebugType, "safeAlloca", &Inst); });
151 break;
152 case AllocaInterestingness::kUninteresting:
153 break;
154 }
155 return;
156 }
157 if (auto *II = dyn_cast<LifetimeIntrinsic>(&Inst)) {
158 AllocaInst *AI = findAllocaForValue(II->getArgOperand(1));
159 if (!AI) {
160 Info.UnrecognizedLifetimes.push_back(&Inst);
161 return;
162 }
163 if (getAllocaInterestingness(*AI) != AllocaInterestingness::kInteresting)
164 return;
165 if (II->getIntrinsicID() == Intrinsic::lifetime_start)
166 Info.AllocasToInstrument[AI].LifetimeStart.push_back(II);
167 else
168 Info.AllocasToInstrument[AI].LifetimeEnd.push_back(II);
169 return;
170 }
171 if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&Inst)) {
172 auto AddIfInteresting = [&](Value *V) {
173 if (auto *AI = dyn_cast_or_null<AllocaInst>(V)) {
174 if (getAllocaInterestingness(*AI) !=
175 AllocaInterestingness::kInteresting)
176 return;
177 AllocaInfo &AInfo = Info.AllocasToInstrument[AI];
178 auto &DVIVec = AInfo.DbgVariableIntrinsics;
179 if (DVIVec.empty() || DVIVec.back() != DVI)
180 DVIVec.push_back(DVI);
181 }
182 };
183 for_each(DVI->location_ops(), AddIfInteresting);
184 if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(DVI))
185 AddIfInteresting(DAI->getAddress());
186 }
187
188 Instruction *ExitUntag = getUntagLocationIfFunctionExit(Inst);
189 if (ExitUntag)
190 Info.RetVec.push_back(ExitUntag);
191 }
192
193 AllocaInterestingness
getAllocaInterestingness(const AllocaInst & AI)194 StackInfoBuilder::getAllocaInterestingness(const AllocaInst &AI) {
195 if (AI.getAllocatedType()->isSized() &&
196 // FIXME: support vscale.
197 !AI.getAllocatedType()->isScalableTy() &&
198 // FIXME: instrument dynamic allocas, too
199 AI.isStaticAlloca() &&
200 // alloca() may be called with 0 size, ignore it.
201 memtag::getAllocaSizeInBytes(AI) > 0 &&
202 // We are only interested in allocas not promotable to registers.
203 // Promotable allocas are common under -O0.
204 !isAllocaPromotable(&AI) &&
205 // inalloca allocas are not treated as static, and we don't want
206 // dynamic alloca instrumentation for them as well.
207 !AI.isUsedWithInAlloca() &&
208 // swifterror allocas are register promoted by ISel
209 !AI.isSwiftError()) {
210 if (!(SSI && SSI->isSafe(AI))) {
211 return AllocaInterestingness::kInteresting;
212 }
213 // safe allocas are not interesting
214 return AllocaInterestingness::kSafe;
215 }
216 return AllocaInterestingness::kUninteresting;
217 }
218
getAllocaSizeInBytes(const AllocaInst & AI)219 uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
220 auto DL = AI.getDataLayout();
221 return *AI.getAllocationSize(DL);
222 }
223
alignAndPadAlloca(memtag::AllocaInfo & Info,llvm::Align Alignment)224 void alignAndPadAlloca(memtag::AllocaInfo &Info, llvm::Align Alignment) {
225 const Align NewAlignment = std::max(Info.AI->getAlign(), Alignment);
226 Info.AI->setAlignment(NewAlignment);
227 auto &Ctx = Info.AI->getFunction()->getContext();
228
229 uint64_t Size = getAllocaSizeInBytes(*Info.AI);
230 uint64_t AlignedSize = alignTo(Size, Alignment);
231 if (Size == AlignedSize)
232 return;
233
234 // Add padding to the alloca.
235 Type *AllocatedType =
236 Info.AI->isArrayAllocation()
237 ? ArrayType::get(
238 Info.AI->getAllocatedType(),
239 cast<ConstantInt>(Info.AI->getArraySize())->getZExtValue())
240 : Info.AI->getAllocatedType();
241 Type *PaddingType = ArrayType::get(Type::getInt8Ty(Ctx), AlignedSize - Size);
242 Type *TypeWithPadding = StructType::get(AllocatedType, PaddingType);
243 auto *NewAI = new AllocaInst(TypeWithPadding, Info.AI->getAddressSpace(),
244 nullptr, "", Info.AI->getIterator());
245 NewAI->takeName(Info.AI);
246 NewAI->setAlignment(Info.AI->getAlign());
247 NewAI->setUsedWithInAlloca(Info.AI->isUsedWithInAlloca());
248 NewAI->setSwiftError(Info.AI->isSwiftError());
249 NewAI->copyMetadata(*Info.AI);
250
251 Value *NewPtr = NewAI;
252
253 // TODO: Remove when typed pointers dropped
254 if (Info.AI->getType() != NewAI->getType())
255 NewPtr = new BitCastInst(NewAI, Info.AI->getType(), "", Info.AI->getIterator());
256
257 Info.AI->replaceAllUsesWith(NewPtr);
258 Info.AI->eraseFromParent();
259 Info.AI = NewAI;
260 }
261
readRegister(IRBuilder<> & IRB,StringRef Name)262 Value *readRegister(IRBuilder<> &IRB, StringRef Name) {
263 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
264 MDNode *MD =
265 MDNode::get(M->getContext(), {MDString::get(M->getContext(), Name)});
266 Value *Args[] = {MetadataAsValue::get(M->getContext(), MD)};
267 return IRB.CreateIntrinsic(Intrinsic::read_register,
268 IRB.getIntPtrTy(M->getDataLayout()), Args);
269 }
270
getPC(const Triple & TargetTriple,IRBuilder<> & IRB)271 Value *getPC(const Triple &TargetTriple, IRBuilder<> &IRB) {
272 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
273 if (TargetTriple.getArch() == Triple::aarch64)
274 return memtag::readRegister(IRB, "pc");
275 return IRB.CreatePtrToInt(IRB.GetInsertBlock()->getParent(),
276 IRB.getIntPtrTy(M->getDataLayout()));
277 }
278
getFP(IRBuilder<> & IRB)279 Value *getFP(IRBuilder<> &IRB) {
280 Function *F = IRB.GetInsertBlock()->getParent();
281 Module *M = F->getParent();
282 return IRB.CreatePtrToInt(
283 IRB.CreateIntrinsic(Intrinsic::frameaddress,
284 IRB.getPtrTy(M->getDataLayout().getAllocaAddrSpace()),
285 {Constant::getNullValue(IRB.getInt32Ty())}),
286 IRB.getIntPtrTy(M->getDataLayout()));
287 }
288
getAndroidSlotPtr(IRBuilder<> & IRB,int Slot)289 Value *getAndroidSlotPtr(IRBuilder<> &IRB, int Slot) {
290 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
291 // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
292 // in Bionic's libc/private/bionic_tls.h.
293 Function *ThreadPointerFunc = Intrinsic::getOrInsertDeclaration(
294 M, Intrinsic::thread_pointer,
295 IRB.getPtrTy(M->getDataLayout().getDefaultGlobalsAddressSpace()));
296 return IRB.CreateConstGEP1_32(IRB.getInt8Ty(),
297 IRB.CreateCall(ThreadPointerFunc), 8 * Slot);
298 }
299
DynCastToDbgAssign(DbgVariableIntrinsic * DVI)300 static DbgAssignIntrinsic *DynCastToDbgAssign(DbgVariableIntrinsic *DVI) {
301 return dyn_cast<DbgAssignIntrinsic>(DVI);
302 }
303
DynCastToDbgAssign(DbgVariableRecord * DVR)304 static DbgVariableRecord *DynCastToDbgAssign(DbgVariableRecord *DVR) {
305 return DVR->isDbgAssign() ? DVR : nullptr;
306 }
307
annotateDebugRecords(AllocaInfo & Info,unsigned int Tag)308 void annotateDebugRecords(AllocaInfo &Info, unsigned int Tag) {
309 // Helper utility for adding DW_OP_LLVM_tag_offset to debug-info records,
310 // abstracted over whether they're intrinsic-stored or DbgVariableRecord
311 // stored.
312 auto AnnotateDbgRecord = [&](auto *DPtr) {
313 // Prepend "tag_offset, N" to the dwarf expression.
314 // Tag offset logically applies to the alloca pointer, and it makes sense
315 // to put it at the beginning of the expression.
316 SmallVector<uint64_t, 8> NewOps = {dwarf::DW_OP_LLVM_tag_offset, Tag};
317 for (size_t LocNo = 0; LocNo < DPtr->getNumVariableLocationOps(); ++LocNo)
318 if (DPtr->getVariableLocationOp(LocNo) == Info.AI)
319 DPtr->setExpression(
320 DIExpression::appendOpsToArg(DPtr->getExpression(), NewOps, LocNo));
321 if (auto *DAI = DynCastToDbgAssign(DPtr)) {
322 if (DAI->getAddress() == Info.AI)
323 DAI->setAddressExpression(
324 DIExpression::prependOpcodes(DAI->getAddressExpression(), NewOps));
325 }
326 };
327
328 llvm::for_each(Info.DbgVariableIntrinsics, AnnotateDbgRecord);
329 llvm::for_each(Info.DbgVariableRecords, AnnotateDbgRecord);
330 }
331
incrementThreadLong(IRBuilder<> & IRB,Value * ThreadLong,unsigned int Inc)332 Value *incrementThreadLong(IRBuilder<> &IRB, Value *ThreadLong,
333 unsigned int Inc) {
334 // Update the ring buffer. Top byte of ThreadLong defines the size of the
335 // buffer in pages, it must be a power of two, and the start of the buffer
336 // must be aligned by twice that much. Therefore wrap around of the ring
337 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
338 // The use of AShr instead of LShr is due to
339 // https://bugs.llvm.org/show_bug.cgi?id=39030
340 // Runtime library makes sure not to use the highest bit.
341 //
342 // Mechanical proof of this address calculation can be found at:
343 // https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/prove_hwasanwrap.smt2
344 //
345 // Example of the wrap case for N = 1
346 // Pointer: 0x01AAAAAAAAAAAFF8
347 // +
348 // 0x0000000000000008
349 // =
350 // 0x01AAAAAAAAAAB000
351 // &
352 // WrapMask: 0xFFFFFFFFFFFFF000
353 // =
354 // 0x01AAAAAAAAAAA000
355 //
356 // Then the WrapMask will be a no-op until the next wrap case.
357 assert((4096 % Inc) == 0);
358 Value *WrapMask = IRB.CreateXor(
359 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
360 ConstantInt::get(ThreadLong->getType(), (uint64_t)-1));
361 return IRB.CreateAnd(
362 IRB.CreateAdd(ThreadLong, ConstantInt::get(ThreadLong->getType(), Inc)),
363 WrapMask);
364 }
365
366 } // namespace memtag
367 } // namespace llvm
368