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 | 36347d917f72eaf2c625369761a8dda95bea10b1 (patch) | |
tree | 48a9697b1cb67045d12f8f749d65464ce6a7c2ca /clang/lib/CodeGen/CGExpr.cpp | |
parent | 9c36859b33b386fbfa9599646de1e2ae01158180 (diff) | |
download | bcm5719-llvm-36347d917f72eaf2c625369761a8dda95bea10b1.tar.gz bcm5719-llvm-36347d917f72eaf2c625369761a8dda95bea10b1.zip |
[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
llvm-svn: 320128
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 88116f7d810..64af2096c98 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/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; } |