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(E->IgnoreImpCasts()); + if (!DRE) + return nullptr; + + auto *PVD = dyn_cast(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(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; } 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: 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; +}