summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/CGExpr.cpp
diff options
context:
space:
mode:
authorVedant Kumar <vsk@apple.com>2017-12-08 01:51:47 +0000
committerVedant Kumar <vsk@apple.com>2017-12-08 01:51:47 +0000
commit3df3793010cdb7099da1e39ea561da360dca22f4 (patch)
treeb8070bb6596316fc39daf72b780e1b5856e1dc00 /lib/CodeGen/CGExpr.cpp
parent8963e92fb3775331f885904a942f18aa1aade982 (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.cpp54
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;
}