]> granicus.if.org Git - clang/commitdiff
[NFC][CodeGen][UBSan] EmitCheckedInBoundsGEP(): refactor EmitGEPOffsetInBytes() helper
authorRoman Lebedev <lebedev.ri@gmail.com>
Fri, 6 Sep 2019 14:18:57 +0000 (14:18 +0000)
committerRoman Lebedev <lebedev.ri@gmail.com>
Fri, 6 Sep 2019 14:18:57 +0000 (14:18 +0000)
It shouldn't really be inlined into the EmitCheckedInBoundsGEP().
Refactoring it beforehand will make follow-up changes more obvious.

This was originally part of https://reviews.llvm.org/D67122

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371207 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprScalar.cpp

index 1221527491e8ecaf3a7e9153599bf36f5fa3e7bf..fc5f07219bf0723f3066ca8b9a07ad13648e5d43 100644 (file)
@@ -4533,31 +4533,24 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
   llvm_unreachable("Unhandled compound assignment operator");
 }
 
-Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
-                                               ArrayRef<Value *> IdxList,
-                                               bool SignedIndices,
-                                               bool IsSubtraction,
-                                               SourceLocation Loc,
-                                               const Twine &Name) {
-  Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
-
-  // If the pointer overflow sanitizer isn't enabled, do nothing.
-  if (!SanOpts.has(SanitizerKind::PointerOverflow))
-    return GEPVal;
-
-  // If the GEP has already been reduced to a constant, leave it be.
-  if (isa<llvm::Constant>(GEPVal))
-    return GEPVal;
-
-  // Only check for overflows in the default address space.
-  if (GEPVal->getType()->getPointerAddressSpace())
-    return GEPVal;
+struct GEPOffsetAndOverflow {
+  // The total (signed) byte offset for the GEP.
+  llvm::Value *TotalOffset;
+  // The offset overflow flag - true if the total offset overflows.
+  llvm::Value *OffsetOverflows;
+};
 
+/// Evaluate given GEPVal, which must be an inbounds GEP,
+/// and compute the total offset it applies from it's base pointer BasePtr.
+/// Returns offset in bytes and a boolean flag whether an overflow happened
+/// during evaluation.
+static GEPOffsetAndOverflow EmitGEPOffsetInBytes(Value *BasePtr, Value *GEPVal,
+                                                 llvm::LLVMContext &VMContext,
+                                                 CodeGenModule &CGM,
+                                                 CGBuilderTy Builder) {
   auto *GEP = cast<llvm::GEPOperator>(GEPVal);
   assert(GEP->isInBounds() && "Expected inbounds GEP");
 
-  SanitizerScope SanScope(this);
-  auto &VMContext = getLLVMContext();
   const auto &DL = CGM.getDataLayout();
   auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
 
@@ -4627,21 +4620,54 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
       TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
   }
 
+  return {TotalOffset, OffsetOverflows};
+}
+
+Value *
+CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, ArrayRef<Value *> IdxList,
+                                        bool SignedIndices, bool IsSubtraction,
+                                        SourceLocation Loc, const Twine &Name) {
+  Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
+
+  // If the pointer overflow sanitizer isn't enabled, do nothing.
+  if (!SanOpts.has(SanitizerKind::PointerOverflow))
+    return GEPVal;
+
+  // If the GEP has already been reduced to a constant, leave it be.
+  if (isa<llvm::Constant>(GEPVal))
+    return GEPVal;
+
+  // Only check for overflows in the default address space.
+  if (GEPVal->getType()->getPointerAddressSpace())
+    return GEPVal;
+
+  SanitizerScope SanScope(this);
+
+  GEPOffsetAndOverflow EvaluatedGEP =
+      EmitGEPOffsetInBytes(Ptr, GEPVal, getLLVMContext(), CGM, Builder);
+
+  auto *GEP = cast<llvm::GEPOperator>(GEPVal);
+
+  const auto &DL = CGM.getDataLayout();
+  auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
+
+  auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
+
   // Common case: if the total offset is zero, don't emit a check.
-  if (TotalOffset == Zero)
+  if (EvaluatedGEP.TotalOffset == Zero)
     return GEPVal;
 
   // Now that we've computed the total offset, add it to the base pointer (with
   // wrapping semantics).
   auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy);
-  auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
+  auto *ComputedGEP = Builder.CreateAdd(IntPtr, EvaluatedGEP.TotalOffset);
 
   // The GEP is valid if:
   // 1) The total offset doesn't overflow, and
   // 2) The sign of the difference between the computed address and the base
   // pointer matches the sign of the total offset.
   llvm::Value *ValidGEP;
-  auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
+  auto *NoOffsetOverflow = Builder.CreateNot(EvaluatedGEP.OffsetOverflows);
   if (SignedIndices) {
     // GEP is computed as `unsigned base + signed offset`, therefore:
     // * If offset was positive, then the computed pointer can not be
@@ -4649,7 +4675,8 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
     // * If offset was negative, then the computed pointer can not be
     //   [unsigned] greater than the bas pointere, unless it overflowed.
     auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
-    auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
+    auto *PosOrZeroOffset =
+        Builder.CreateICmpSGE(EvaluatedGEP.TotalOffset, Zero);
     llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
     ValidGEP = Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid);
   } else if (!IsSubtraction) {