diff options
author | Vedant Kumar <vsk@apple.com> | 2017-12-08 01:51:47 +0000 |
---|---|---|
committer | Vedant Kumar <vsk@apple.com> | 2017-12-08 01:51:47 +0000 |
commit | 3df3793010cdb7099da1e39ea561da360dca22f4 (patch) | |
tree | b8070bb6596316fc39daf72b780e1b5856e1dc00 /lib/CodeGen/CGExpr.cpp | |
parent | 8963e92fb3775331f885904a942f18aa1aade982 (diff) |
[ubsan] Use pass_object_size info in bounds checks
Teach UBSan's bounds check to opportunistically use pass_object_size
information to check array accesses.
rdar://33272922
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320128 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExpr.cpp')
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 88116f7d81..64af2096c9 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -814,6 +814,53 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { return false; } +llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E, + QualType EltTy) { + ASTContext &C = getContext(); + uint64_t EltSize = C.getTypeSizeInChars(EltTy).getQuantity(); + if (!EltSize) + return nullptr; + + auto *ArrayDeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); + if (!ArrayDeclRef) + return nullptr; + + auto *ParamDecl = dyn_cast<ParmVarDecl>(ArrayDeclRef->getDecl()); + if (!ParamDecl) + return nullptr; + + // Arrays don't have pass_object_size attributes, but if they have a constant + // size modifier it's the array size (C99 6.5.7.2p1). + if (auto *DecayedArrayTy = dyn_cast<DecayedType>(ParamDecl->getType())) + if (auto *ArrayTy = + dyn_cast<ConstantArrayType>(DecayedArrayTy->getOriginalType())) + return llvm::ConstantInt::get(SizeTy, + ArrayTy->getSize().getLimitedValue()); + + auto *POSAttr = ParamDecl->getAttr<PassObjectSizeAttr>(); + if (!POSAttr) + return nullptr; + + // Don't load the size if it's a lower bound. + int POSType = POSAttr->getType(); + if (POSType != 0 && POSType != 1) + return nullptr; + + // Find the implicit size parameter. + auto PassedSizeIt = SizeArguments.find(ParamDecl); + if (PassedSizeIt == SizeArguments.end()) + return nullptr; + + const ImplicitParamDecl *PassedSizeDecl = PassedSizeIt->second; + assert(LocalDeclMap.count(PassedSizeDecl) && "Passed size not loadable"); + Address AddrOfSize = LocalDeclMap.find(PassedSizeDecl)->second; + llvm::Value *SizeInBytes = EmitLoadOfScalar(AddrOfSize, /*Volatile=*/false, + C.getSizeType(), E->getExprLoc()); + llvm::Value *SizeOfElement = + llvm::ConstantInt::get(SizeInBytes->getType(), EltSize); + 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 +882,16 @@ static llvm::Value *getArrayIndexingBound( 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; } |