120ea6252SNuno Lopes //===- BoundsChecking.cpp - Instrumentation for run-time bounds checking --===//
220ea6252SNuno Lopes //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
620ea6252SNuno Lopes //
720ea6252SNuno Lopes //===----------------------------------------------------------------------===//
820ea6252SNuno Lopes 
900a301d5SChandler Carruth #include "llvm/Transforms/Instrumentation/BoundsChecking.h"
10ed0881b2SChandler Carruth #include "llvm/ADT/Statistic.h"
11bff0ef03SEugene Zelenko #include "llvm/ADT/Twine.h"
12ed0881b2SChandler Carruth #include "llvm/Analysis/MemoryBuiltins.h"
138dbcc589SJoel Galenson #include "llvm/Analysis/ScalarEvolution.h"
14452a0074SChandler Carruth #include "llvm/Analysis/TargetFolder.h"
15799003bfSBenjamin Kramer #include "llvm/Analysis/TargetLibraryInfo.h"
16bff0ef03SEugene Zelenko #include "llvm/IR/BasicBlock.h"
17bff0ef03SEugene Zelenko #include "llvm/IR/Constants.h"
189fb823bbSChandler Carruth #include "llvm/IR/DataLayout.h"
19bff0ef03SEugene Zelenko #include "llvm/IR/Function.h"
209fb823bbSChandler Carruth #include "llvm/IR/IRBuilder.h"
218394857fSChandler Carruth #include "llvm/IR/InstIterator.h"
22bff0ef03SEugene Zelenko #include "llvm/IR/Instruction.h"
23bff0ef03SEugene Zelenko #include "llvm/IR/Instructions.h"
249fb823bbSChandler Carruth #include "llvm/IR/Intrinsics.h"
25bff0ef03SEugene Zelenko #include "llvm/IR/Value.h"
2605da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
2720ea6252SNuno Lopes #include "llvm/Pass.h"
28bff0ef03SEugene Zelenko #include "llvm/Support/Casting.h"
2920ea6252SNuno Lopes #include "llvm/Support/CommandLine.h"
3020ea6252SNuno Lopes #include "llvm/Support/Debug.h"
3120ea6252SNuno Lopes #include "llvm/Support/raw_ostream.h"
32bff0ef03SEugene Zelenko #include <cstdint>
339efe89d8SSimon Pilgrim #include <utility>
34bff0ef03SEugene Zelenko 
3520ea6252SNuno Lopes using namespace llvm;
3620ea6252SNuno Lopes 
37964daaafSChandler Carruth #define DEBUG_TYPE "bounds-checking"
38964daaafSChandler Carruth 
3920ea6252SNuno Lopes static cl::opt<bool> SingleTrapBB("bounds-checking-single-trap",
4020ea6252SNuno Lopes                                   cl::desc("Use one trap block per function"));
4120ea6252SNuno Lopes 
4220ea6252SNuno Lopes STATISTIC(ChecksAdded, "Bounds checks added");
4320ea6252SNuno Lopes STATISTIC(ChecksSkipped, "Bounds checks skipped");
4420ea6252SNuno Lopes STATISTIC(ChecksUnable, "Bounds checks unable to add");
4520ea6252SNuno Lopes 
46bff0ef03SEugene Zelenko using BuilderTy = IRBuilder<TargetFolder>;
4720ea6252SNuno Lopes 
48cfe5bc15SJoel Galenson /// Gets the conditions under which memory accessing instructions will overflow.
491594feeaSChandler Carruth ///
501594feeaSChandler Carruth /// \p Ptr is the pointer that will be read/written, and \p InstVal is either
511594feeaSChandler Carruth /// the result from the load or the value being stored. It is used to determine
521594feeaSChandler Carruth /// the size of memory block that is touched.
531594feeaSChandler Carruth ///
54cfe5bc15SJoel Galenson /// Returns the condition under which the access will overflow.
getBoundsCheckCond(Value * Ptr,Value * InstVal,const DataLayout & DL,TargetLibraryInfo & TLI,ObjectSizeOffsetEvaluator & ObjSizeEval,BuilderTy & IRB,ScalarEvolution & SE)55cfe5bc15SJoel Galenson static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal,
561594feeaSChandler Carruth                                  const DataLayout &DL, TargetLibraryInfo &TLI,
571594feeaSChandler Carruth                                  ObjectSizeOffsetEvaluator &ObjSizeEval,
58cfe5bc15SJoel Galenson                                  BuilderTy &IRB, ScalarEvolution &SE) {
59a28d91d8SMehdi Amini   uint64_t NeededSize = DL.getTypeStoreSize(InstVal->getType());
60d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
6120ea6252SNuno Lopes                     << " bytes\n");
6220ea6252SNuno Lopes 
631594feeaSChandler Carruth   SizeOffsetEvalType SizeOffset = ObjSizeEval.compute(Ptr);
6420ea6252SNuno Lopes 
651594feeaSChandler Carruth   if (!ObjSizeEval.bothKnown(SizeOffset)) {
6620ea6252SNuno Lopes     ++ChecksUnable;
67cfe5bc15SJoel Galenson     return nullptr;
6820ea6252SNuno Lopes   }
6920ea6252SNuno Lopes 
7020ea6252SNuno Lopes   Value *Size   = SizeOffset.first;
7120ea6252SNuno Lopes   Value *Offset = SizeOffset.second;
7220ea6252SNuno Lopes   ConstantInt *SizeCI = dyn_cast<ConstantInt>(Size);
7320ea6252SNuno Lopes 
74a28d91d8SMehdi Amini   Type *IntTy = DL.getIntPtrType(Ptr->getType());
7520ea6252SNuno Lopes   Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
7620ea6252SNuno Lopes 
778dbcc589SJoel Galenson   auto SizeRange = SE.getUnsignedRange(SE.getSCEV(Size));
788dbcc589SJoel Galenson   auto OffsetRange = SE.getUnsignedRange(SE.getSCEV(Offset));
798dbcc589SJoel Galenson   auto NeededSizeRange = SE.getUnsignedRange(SE.getSCEV(NeededSizeVal));
808dbcc589SJoel Galenson 
8120ea6252SNuno Lopes   // three checks are required to ensure safety:
8220ea6252SNuno Lopes   // . Offset >= 0  (since the offset is given from the base ptr)
8320ea6252SNuno Lopes   // . Size >= Offset  (unsigned)
8420ea6252SNuno Lopes   // . Size - Offset >= NeededSize  (unsigned)
8520ea6252SNuno Lopes   //
8620ea6252SNuno Lopes   // optimization: if Size >= 0 (signed), skip 1st check
8720ea6252SNuno Lopes   // FIXME: add NSW/NUW here?  -- we dont care if the subtraction overflows
881594feeaSChandler Carruth   Value *ObjSize = IRB.CreateSub(Size, Offset);
898dbcc589SJoel Galenson   Value *Cmp2 = SizeRange.getUnsignedMin().uge(OffsetRange.getUnsignedMax())
908dbcc589SJoel Galenson                     ? ConstantInt::getFalse(Ptr->getContext())
918dbcc589SJoel Galenson                     : IRB.CreateICmpULT(Size, Offset);
928dbcc589SJoel Galenson   Value *Cmp3 = SizeRange.sub(OffsetRange)
938dbcc589SJoel Galenson                         .getUnsignedMin()
948dbcc589SJoel Galenson                         .uge(NeededSizeRange.getUnsignedMax())
958dbcc589SJoel Galenson                     ? ConstantInt::getFalse(Ptr->getContext())
968dbcc589SJoel Galenson                     : IRB.CreateICmpULT(ObjSize, NeededSizeVal);
971594feeaSChandler Carruth   Value *Or = IRB.CreateOr(Cmp2, Cmp3);
988dbcc589SJoel Galenson   if ((!SizeCI || SizeCI->getValue().slt(0)) &&
998dbcc589SJoel Galenson       !SizeRange.getSignedMin().isNonNegative()) {
1001594feeaSChandler Carruth     Value *Cmp1 = IRB.CreateICmpSLT(Offset, ConstantInt::get(IntTy, 0));
1011594feeaSChandler Carruth     Or = IRB.CreateOr(Cmp1, Or);
10220ea6252SNuno Lopes   }
10320ea6252SNuno Lopes 
104cfe5bc15SJoel Galenson   return Or;
105cfe5bc15SJoel Galenson }
106cfe5bc15SJoel Galenson 
107cfe5bc15SJoel Galenson /// Adds run-time bounds checks to memory accessing instructions.
108cfe5bc15SJoel Galenson ///
109cfe5bc15SJoel Galenson /// \p Or is the condition that should guard the trap.
110cfe5bc15SJoel Galenson ///
111cfe5bc15SJoel Galenson /// \p GetTrapBB is a callable that returns the trap BB to use on failure.
112cfe5bc15SJoel Galenson template <typename GetTrapBBT>
insertBoundsCheck(Value * Or,BuilderTy & IRB,GetTrapBBT GetTrapBB)1137c362b25SNikita Popov static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) {
1143f0e056dSChandler Carruth   // check if the comparison is always false
1153f0e056dSChandler Carruth   ConstantInt *C = dyn_cast_or_null<ConstantInt>(Or);
1163f0e056dSChandler Carruth   if (C) {
1173f0e056dSChandler Carruth     ++ChecksSkipped;
1183f0e056dSChandler Carruth     // If non-zero, nothing to do.
1193f0e056dSChandler Carruth     if (!C->getZExtValue())
120cfe5bc15SJoel Galenson       return;
1213f0e056dSChandler Carruth   }
1223f0e056dSChandler Carruth   ++ChecksAdded;
1233f0e056dSChandler Carruth 
1241594feeaSChandler Carruth   BasicBlock::iterator SplitI = IRB.GetInsertPoint();
1253f0e056dSChandler Carruth   BasicBlock *OldBB = SplitI->getParent();
1263f0e056dSChandler Carruth   BasicBlock *Cont = OldBB->splitBasicBlock(SplitI);
1273f0e056dSChandler Carruth   OldBB->getTerminator()->eraseFromParent();
1283f0e056dSChandler Carruth 
1293f0e056dSChandler Carruth   if (C) {
1303f0e056dSChandler Carruth     // If we have a constant zero, unconditionally branch.
1313f0e056dSChandler Carruth     // FIXME: We should really handle this differently to bypass the splitting
1323f0e056dSChandler Carruth     // the block.
1331594feeaSChandler Carruth     BranchInst::Create(GetTrapBB(IRB), OldBB);
134cfe5bc15SJoel Galenson     return;
1353f0e056dSChandler Carruth   }
1363f0e056dSChandler Carruth 
1373f0e056dSChandler Carruth   // Create the conditional branch.
1381594feeaSChandler Carruth   BranchInst::Create(GetTrapBB(IRB), Cont, Or, OldBB);
13920ea6252SNuno Lopes }
14020ea6252SNuno Lopes 
addBoundsChecking(Function & F,TargetLibraryInfo & TLI,ScalarEvolution & SE)1418dbcc589SJoel Galenson static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
1428dbcc589SJoel Galenson                               ScalarEvolution &SE) {
143*17ce89faSTong Zhang   if (F.hasFnAttribute(Attribute::NoSanitizeBounds))
144*17ce89faSTong Zhang     return false;
145*17ce89faSTong Zhang 
146a28d91d8SMehdi Amini   const DataLayout &DL = F.getParent()->getDataLayout();
147600e9deaSErik Pilkington   ObjectSizeOpts EvalOpts;
148600e9deaSErik Pilkington   EvalOpts.RoundToAlign = true;
149600e9deaSErik Pilkington   ObjectSizeOffsetEvaluator ObjSizeEval(DL, &TLI, F.getContext(), EvalOpts);
15020ea6252SNuno Lopes 
15120ea6252SNuno Lopes   // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
15220ea6252SNuno Lopes   // touching instructions
153cfe5bc15SJoel Galenson   SmallVector<std::pair<Instruction *, Value *>, 4> TrapInfo;
1541594feeaSChandler Carruth   for (Instruction &I : instructions(F)) {
155cfe5bc15SJoel Galenson     Value *Or = nullptr;
156cfe5bc15SJoel Galenson     BuilderTy IRB(I.getParent(), BasicBlock::iterator(&I), TargetFolder(DL));
157cfe5bc15SJoel Galenson     if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
15804bd2c37SVitaly Buka       if (!LI->isVolatile())
159cfe5bc15SJoel Galenson         Or = getBoundsCheckCond(LI->getPointerOperand(), LI, DL, TLI,
160cfe5bc15SJoel Galenson                                 ObjSizeEval, IRB, SE);
161cfe5bc15SJoel Galenson     } else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
16204bd2c37SVitaly Buka       if (!SI->isVolatile())
163cfe5bc15SJoel Galenson         Or = getBoundsCheckCond(SI->getPointerOperand(), SI->getValueOperand(),
164cfe5bc15SJoel Galenson                                 DL, TLI, ObjSizeEval, IRB, SE);
165cfe5bc15SJoel Galenson     } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(&I)) {
16604bd2c37SVitaly Buka       if (!AI->isVolatile())
16704bd2c37SVitaly Buka         Or =
16804bd2c37SVitaly Buka             getBoundsCheckCond(AI->getPointerOperand(), AI->getCompareOperand(),
169cfe5bc15SJoel Galenson                                DL, TLI, ObjSizeEval, IRB, SE);
170cfe5bc15SJoel Galenson     } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(&I)) {
17104bd2c37SVitaly Buka       if (!AI->isVolatile())
17204bd2c37SVitaly Buka         Or = getBoundsCheckCond(AI->getPointerOperand(), AI->getValOperand(),
17304bd2c37SVitaly Buka                                 DL, TLI, ObjSizeEval, IRB, SE);
174cfe5bc15SJoel Galenson     }
175cfe5bc15SJoel Galenson     if (Or)
176cfe5bc15SJoel Galenson       TrapInfo.push_back(std::make_pair(&I, Or));
17720ea6252SNuno Lopes   }
17820ea6252SNuno Lopes 
1791594feeaSChandler Carruth   // Create a trapping basic block on demand using a callback. Depending on
1801594feeaSChandler Carruth   // flags, this will either create a single block for the entire function or
1811594feeaSChandler Carruth   // will create a fresh block every time it is called.
1821594feeaSChandler Carruth   BasicBlock *TrapBB = nullptr;
1831594feeaSChandler Carruth   auto GetTrapBB = [&TrapBB](BuilderTy &IRB) {
1841594feeaSChandler Carruth     if (TrapBB && SingleTrapBB)
1851594feeaSChandler Carruth       return TrapBB;
18620ea6252SNuno Lopes 
1871594feeaSChandler Carruth     Function *Fn = IRB.GetInsertBlock()->getParent();
1881594feeaSChandler Carruth     // FIXME: This debug location doesn't make a lot of sense in the
1891594feeaSChandler Carruth     // `SingleTrapBB` case.
1901594feeaSChandler Carruth     auto DebugLoc = IRB.getCurrentDebugLocation();
1911594feeaSChandler Carruth     IRBuilder<>::InsertPointGuard Guard(IRB);
1921594feeaSChandler Carruth     TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
1931594feeaSChandler Carruth     IRB.SetInsertPoint(TrapBB);
1941594feeaSChandler Carruth 
1951594feeaSChandler Carruth     auto *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
1961594feeaSChandler Carruth     CallInst *TrapCall = IRB.CreateCall(F, {});
1971594feeaSChandler Carruth     TrapCall->setDoesNotReturn();
1981594feeaSChandler Carruth     TrapCall->setDoesNotThrow();
1991594feeaSChandler Carruth     TrapCall->setDebugLoc(DebugLoc);
2001594feeaSChandler Carruth     IRB.CreateUnreachable();
2011594feeaSChandler Carruth 
2021594feeaSChandler Carruth     return TrapBB;
2031594feeaSChandler Carruth   };
2041594feeaSChandler Carruth 
205cfe5bc15SJoel Galenson   // Add the checks.
206cfe5bc15SJoel Galenson   for (const auto &Entry : TrapInfo) {
207cfe5bc15SJoel Galenson     Instruction *Inst = Entry.first;
2081594feeaSChandler Carruth     BuilderTy IRB(Inst->getParent(), BasicBlock::iterator(Inst), TargetFolder(DL));
209cfe5bc15SJoel Galenson     insertBoundsCheck(Entry.second, IRB, GetTrapBB);
21020ea6252SNuno Lopes   }
211cfe5bc15SJoel Galenson 
212cfe5bc15SJoel Galenson   return !TrapInfo.empty();
21320ea6252SNuno Lopes }
21420ea6252SNuno Lopes 
run(Function & F,FunctionAnalysisManager & AM)21500a301d5SChandler Carruth PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &AM) {
21600a301d5SChandler Carruth   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
2178dbcc589SJoel Galenson   auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
21800a301d5SChandler Carruth 
2198dbcc589SJoel Galenson   if (!addBoundsChecking(F, TLI, SE))
22000a301d5SChandler Carruth     return PreservedAnalyses::all();
22100a301d5SChandler Carruth 
22200a301d5SChandler Carruth   return PreservedAnalyses::none();
22300a301d5SChandler Carruth }
22400a301d5SChandler Carruth 
22500a301d5SChandler Carruth namespace {
22600a301d5SChandler Carruth struct BoundsCheckingLegacyPass : public FunctionPass {
22700a301d5SChandler Carruth   static char ID;
22800a301d5SChandler Carruth 
BoundsCheckingLegacyPass__anon376f97280211::BoundsCheckingLegacyPass22900a301d5SChandler Carruth   BoundsCheckingLegacyPass() : FunctionPass(ID) {
23000a301d5SChandler Carruth     initializeBoundsCheckingLegacyPassPass(*PassRegistry::getPassRegistry());
23100a301d5SChandler Carruth   }
23200a301d5SChandler Carruth 
runOnFunction__anon376f97280211::BoundsCheckingLegacyPass23300a301d5SChandler Carruth   bool runOnFunction(Function &F) override {
2349c27b59cSTeresa Johnson     auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
2358dbcc589SJoel Galenson     auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
2368dbcc589SJoel Galenson     return addBoundsChecking(F, TLI, SE);
23700a301d5SChandler Carruth   }
23800a301d5SChandler Carruth 
getAnalysisUsage__anon376f97280211::BoundsCheckingLegacyPass23900a301d5SChandler Carruth   void getAnalysisUsage(AnalysisUsage &AU) const override {
24000a301d5SChandler Carruth     AU.addRequired<TargetLibraryInfoWrapperPass>();
2418dbcc589SJoel Galenson     AU.addRequired<ScalarEvolutionWrapperPass>();
24200a301d5SChandler Carruth   }
24300a301d5SChandler Carruth };
24400a301d5SChandler Carruth } // namespace
24500a301d5SChandler Carruth 
24600a301d5SChandler Carruth char BoundsCheckingLegacyPass::ID = 0;
24700a301d5SChandler Carruth INITIALIZE_PASS_BEGIN(BoundsCheckingLegacyPass, "bounds-checking",
24800a301d5SChandler Carruth                       "Run-time bounds checking", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)24900a301d5SChandler Carruth INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
25000a301d5SChandler Carruth INITIALIZE_PASS_END(BoundsCheckingLegacyPass, "bounds-checking",
25100a301d5SChandler Carruth                     "Run-time bounds checking", false, false)
25200a301d5SChandler Carruth 
25300a301d5SChandler Carruth FunctionPass *llvm::createBoundsCheckingLegacyPass() {
25400a301d5SChandler Carruth   return new BoundsCheckingLegacyPass();
25520ea6252SNuno Lopes }
256