From 910f17e331221cd0833d0b5b49013cbbc7ef122a Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Tue, 14 May 2013 21:59:17 +0000 Subject: [PATCH] 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 --- lib/AST/ASTContext.cpp | 23 +++++++++++++++++++++-- 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 +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair 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 ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair 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); -- 2.40.0