diff options
author | Richard Trieu <rtrieu@google.com> | 2013-05-14 21:59:17 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2013-05-14 21:59:17 +0000 |
commit | 910f17e331221cd0833d0b5b49013cbbc7ef122a (patch) | |
tree | c92ef3acd6ef3e0cafb90f856a3de6c0ef96bb09 | |
parent | e7e94c907cf6924929e81083e93628d0f520c734 (diff) | |
download | clang-910f17e331221cd0833d0b5b49013cbbc7ef122a.tar.gz clang-910f17e331221cd0833d0b5b49013cbbc7ef122a.tar.bz2 clang-910f17e331221cd0833d0b5b49013cbbc7ef122a.tar.xz |
When computing the size of large arrays, use char units instead of bits.
This prevents an overflow and assertion when the number of bits cannot be
stored in 64-bits.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181839 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/AST/ASTContext.cpp | 23 | ||||
-rw-r--r-- | test/Sema/offsetof.c | 12 |
2 files changed, 33 insertions, 2 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 21a16a6d98..c385d6cf3a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1345,8 +1345,27 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { return sizeAndAlign; } +/// getConstantArrayInfoInChars - Performing the computation in CharUnits +/// instead of in bits prevents overflowing the uint64_t for some large arrays. +std::pair<CharUnits, CharUnits> +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair<CharUnits, CharUnits> EltInfo = + Context.getTypeInfoInChars(CAT->getElementType()); + uint64_t Size = CAT->getSize().getZExtValue(); + assert((Size == 0 || EltInfo.first.getQuantity() <= (uint64_t)(-1)/Size) && + "Overflow in array type char size evaluation"); + uint64_t Width = EltInfo.first.getQuantity() * Size; + unsigned Align = EltInfo.second.getQuantity(); + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(CharUnits::fromQuantity(Width), + CharUnits::fromQuantity(Align)); +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair<uint64_t, unsigned> Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); @@ -1702,10 +1721,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c index 46fb515c7f..4e7fd7f29e 100644 --- a/test/Sema/offsetof.c +++ b/test/Sema/offsetof.c @@ -69,3 +69,15 @@ int test4 = __builtin_offsetof(Array, array); int test5() { return __builtin_offsetof(Array, array[*(int*)0]); // expected-warning{{indirection of non-volatile null pointer}} expected-note{{__builtin_trap}} } + +// PR15216 +// Don't crash when taking computing the offset of structs with large arrays. +const unsigned long Size = (1l << 62); + +struct Chunk { + char padding[Size]; + char more_padding[1][Size]; + char data; +}; + +int test6 = __builtin_offsetof(struct Chunk, data); |