[PATCH] D40940: [ubsan] Use pass_object_size info in bounds checks

Vedant Kumar via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 6 19:45:26 PST 2017


vsk created this revision.
Herald added a reviewer: george.burgess.iv.

Teach UBSan's bounds check to opportunistically use pass_object_size
information to check array accesses.

rdar://33272922


https://reviews.llvm.org/D40940

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/ubsan-pass-object-size.c


Index: test/CodeGen/ubsan-pass-object-size.c
===================================================================
--- /dev/null
+++ test/CodeGen/ubsan-pass-object-size.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin10 -fsanitize=array-bounds -o - | FileCheck %s
+
+// CHECK-LABEL: define i32 @foo(
+int foo(int *const p __attribute__((pass_object_size(0))), int n) {
+  int x = p[n];
+
+  // CHECK: [[SIZE_ALLOCA:%.*]] = alloca i64, align 8
+  // CHECK: store i64 %{{.*}}, i64* [[SIZE_ALLOCA]], align 8
+  // CHECK: [[LOAD_SIZE:%.*]] = load i64, i64* [[SIZE_ALLOCA]], align 8, !nosanitize
+  // CHECK-NEXT: [[SCALED_SIZE:%.*]] = udiv i64 [[LOAD_SIZE]], 4, !nosanitize
+  // CHECK-NEXT: [[SEXT_N:%.*]] = sext i32 %{{.*}} to i64, !nosanitize
+  // CHECK-NEXT: [[ICMP:%.*]] = icmp ult i64 [[SEXT_N]], [[SCALED_SIZE]], !nosanitize
+  // CHECK-NEXT: br i1 [[ICMP]], {{.*}} !nosanitize
+  // CHECK: __ubsan_handle_out_of_bounds
+
+  {
+    int *p = &n; // Shadow the parameter.
+    // CHECK-NOT: __ubsan_handle_out_of_bounds
+    x = p[n];
+  }
+
+  // CHECK: ret i32
+  return x;
+}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3932,6 +3932,10 @@
                                    LValueBaseInfo *BaseInfo = nullptr,
                                    TBAAAccessInfo *TBAAInfo = nullptr);
 
+  /// If \p E references a parameter with pass_object_size info, load the
+  /// object size and divide by the size of \p EltTy. Otherwise return null.
+  llvm::Value *LoadPassedObjectSize(const Expr *E, QualType EltTy);
+
   void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
 
 private:
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -814,6 +814,32 @@
   return false;
 }
 
+llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
+                                                   QualType EltTy) {
+  auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImpCasts());
+  if (!DRE)
+    return nullptr;
+
+  auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl());
+  if (!PVD)
+    return nullptr;
+
+  // Find the implicit size parameter.
+  auto SizeDeclIt = SizeArguments.find(PVD);
+  if (SizeDeclIt == SizeArguments.end())
+    return nullptr;
+
+  ASTContext &C = getContext();
+  const ImplicitParamDecl *IPD = SizeDeclIt->second;
+  assert(LocalDeclMap.count(IPD) && "Passed object size not loadable");
+  Address AddrOfSize = LocalDeclMap.find(IPD)->second;
+  llvm::Value *SizeInBytes = EmitLoadOfScalar(AddrOfSize, /*Volatile=*/false,
+                                              C.getSizeType(), E->getExprLoc());
+  llvm::Value *SizeOfElement = llvm::ConstantInt::get(
+      SizeInBytes->getType(), C.getTypeSizeInChars(EltTy).getQuantity());
+  return Builder.CreateUDiv(SizeInBytes, SizeOfElement);
+}
+
 /// If Base is known to point to the start of an array, return the length of
 /// that array. Return 0 if the length cannot be determined.
 static llvm::Value *getArrayIndexingBound(
@@ -835,9 +861,16 @@
         return CGF.Builder.getInt(CAT->getSize());
       else if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
         return CGF.getVLASize(VAT).first;
+      // Ignore pass_object_size here. It's not applicable on decayed pointers.
     }
   }
 
+  QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0};
+  if (llvm::Value *POS = CGF.LoadPassedObjectSize(Base, EltTy)) {
+    IndexedType = Base->getType();
+    return POS;
+  }
+
   return nullptr;
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D40940.125880.patch
Type: text/x-patch
Size: 3675 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171207/a1689f4a/attachment.bin>


More information about the cfe-commits mailing list