[cfe-commits] r111338 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Type.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaType.cpp test/Sema/array-size-64.c test/Sema/array-size.c
Douglas Gregor
dgregor at apple.com
Tue Aug 17 17:39:00 PDT 2010
Author: dgregor
Date: Tue Aug 17 19:39:00 2010
New Revision: 111338
URL: http://llvm.org/viewvc/llvm-project?rev=111338&view=rev
Log:
Emit an error if an array is too large. We're slightly more strict
than GCC 4.2 here when building 32-bit (where GCC will allow
allocation of an array for which we can't get a valid past-the-end
pointer), and emulate its odd behavior in 64-bit where it only allows
63 bits worth of storage in the array. The former is a correctness
issue; the latter is harmless in practice (you wouldn't be able to use
such an array anyway) and helps us pass a GCC DejaGNU test.
Fixes <rdar://problem/8212293>.
Added:
cfe/trunk/test/Sema/array-size-64.c (with props)
cfe/trunk/test/Sema/array-size.c (with props)
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Tue Aug 17 19:39:00 2010
@@ -1458,6 +1458,17 @@
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+
+ /// \brief Determine the number of bits required to address a member of
+ // an array with the given element type and number of elements.
+ static unsigned getNumAddressingBits(ASTContext &Context,
+ QualType ElementType,
+ const llvm::APInt &NumElements);
+
+ /// \brief Determine the maximum number of active bits that an array's size
+ /// can require, which limits the maximum size of the array.
+ static unsigned getMaxSizeBits(ASTContext &Context);
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getElementType(), getSize(),
getSizeModifier(), getIndexTypeCVRQualifiers());
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug 17 19:39:00 2010
@@ -1797,6 +1797,8 @@
"extension will never be supported">;
def err_vm_func_decl : Error<
"function declaration cannot have variably modified type">;
+def err_array_too_large : Error<
+ "array is too large (%0 elements)">;
def err_typecheck_negative_array_size : Error<"array size is negative">;
def warn_typecheck_function_qualifiers : Warning<
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Aug 17 19:39:00 2010
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -21,6 +22,7 @@
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
using namespace clang;
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
@@ -35,6 +37,32 @@
Type::~Type() { }
+unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
+ QualType ElementType,
+ const llvm::APInt &NumElements) {
+ llvm::APSInt SizeExtended(NumElements, true);
+ unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType());
+ SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2);
+
+ uint64_t ElementSize
+ = Context.getTypeSizeInChars(ElementType).getQuantity();
+ llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize));
+ TotalSize *= SizeExtended;
+
+ return TotalSize.getActiveBits();
+}
+
+unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) {
+ unsigned Bits = Context.getTypeSize(Context.getSizeType());
+
+ // GCC appears to only allow 63 bits worth of address space when compiling
+ // for 64-bit, so we do the same.
+ if (Bits == 64)
+ --Bits;
+
+ return Bits;
+}
+
void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
ASTContext &Context,
QualType ET,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 17 19:39:00 2010
@@ -2364,20 +2364,26 @@
/// be errors (for GCC compatibility).
static QualType TryToFixInvalidVariablyModifiedType(QualType T,
ASTContext &Context,
- bool &SizeIsNegative) {
+ bool &SizeIsNegative,
+ llvm::APSInt &Oversized) {
// This method tries to turn a variable array into a constant
// array even when the size isn't an ICE. This is necessary
// for compatibility with code that depends on gcc's buggy
// constant expression folding, like struct {char x[(int)(char*)2];}
SizeIsNegative = false;
-
+ Oversized = 0;
+
+ if (T->isDependentType())
+ return QualType();
+
QualifierCollector Qs;
const Type *Ty = Qs.strip(T);
if (const PointerType* PTy = dyn_cast<PointerType>(Ty)) {
QualType Pointee = PTy->getPointeeType();
QualType FixedType =
- TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative);
+ TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative,
+ Oversized);
if (FixedType.isNull()) return FixedType;
FixedType = Context.getPointerType(FixedType);
return Qs.apply(FixedType);
@@ -2396,15 +2402,24 @@
!EvalResult.Val.isInt())
return QualType();
+ // Check whether the array size is negative.
llvm::APSInt &Res = EvalResult.Val.getInt();
- if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) {
- // TODO: preserve the size expression in declarator info
- return Context.getConstantArrayType(VLATy->getElementType(),
- Res, ArrayType::Normal, 0);
+ if (Res.isSigned() && Res.isNegative()) {
+ SizeIsNegative = true;
+ return QualType();
}
- SizeIsNegative = true;
- return QualType();
+ // Check whether the array is too large to be addressed.
+ unsigned ActiveSizeBits
+ = ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(),
+ Res);
+ if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
+ Oversized = Res;
+ return QualType();
+ }
+
+ return Context.getConstantArrayType(VLATy->getElementType(),
+ Res, ArrayType::Normal, 0);
}
/// \brief Register the given locally-scoped external C declaration so
@@ -2501,8 +2516,10 @@
if (S->getFnParent() == 0) {
bool SizeIsNegative;
+ llvm::APSInt Oversized;
QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
+ TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
+ Oversized);
if (!FixedTy.isNull()) {
Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size);
NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy));
@@ -2511,6 +2528,9 @@
Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size);
else if (T->isVariableArrayType())
Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope);
+ else if (Oversized.getBoolValue())
+ Diag(D.getIdentifierLoc(), diag::err_array_too_large)
+ << Oversized.toString(10);
else
Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope);
NewTD->setInvalidDecl();
@@ -2931,8 +2951,10 @@
if ((isVM && NewVD->hasLinkage()) ||
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
bool SizeIsNegative;
+ llvm::APSInt Oversized;
QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
+ TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
+ Oversized);
if (FixedTy.isNull() && T->isVariableArrayType()) {
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
@@ -5965,14 +5987,19 @@
// than a variably modified type.
if (!InvalidDecl && T->isVariablyModifiedType()) {
bool SizeIsNegative;
+ llvm::APSInt Oversized;
QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context,
- SizeIsNegative);
+ SizeIsNegative,
+ Oversized);
if (!FixedTy.isNull()) {
Diag(Loc, diag::warn_illegal_constant_array_size);
T = FixedTy;
} else {
if (SizeIsNegative)
Diag(Loc, diag::err_typecheck_negative_array_size);
+ else if (Oversized.getBoolValue())
+ Diag(Loc, diag::err_array_too_large)
+ << Oversized.toString(10);
else
Diag(Loc, diag::err_typecheck_field_variable_size);
InvalidDecl = true;
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Aug 17 19:39:00 2010
@@ -716,8 +716,20 @@
llvm::APInt::getNullValue(Value.getBitWidth()),
Value.isUnsigned()))
return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
- diag::err_typecheck_negative_array_size)
+ diag::err_typecheck_negative_array_size)
<< ArraySize->getSourceRange());
+
+ if (!AllocType->isDependentType()) {
+ unsigned ActiveSizeBits
+ = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
+ if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
+ Diag(ArraySize->getSourceRange().getBegin(),
+ diag::err_array_too_large)
+ << Value.toString(10)
+ << ArraySize->getSourceRange();
+ return ExprError();
+ }
+ }
} else if (TypeIdParens.isValid()) {
// Can't have dynamic array size when the type-id is in parentheses.
Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst)
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=111338&r1=111337&r2=111338&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Aug 17 19:39:00 2010
@@ -677,7 +677,7 @@
<< ArraySize->getType() << ArraySize->getSourceRange();
return QualType();
}
- llvm::APSInt ConstVal(32);
+ llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType()));
if (!ArraySize) {
if (ASM == ArrayType::Star)
T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
@@ -707,7 +707,17 @@
isSFINAEContext()? diag::err_typecheck_zero_array_size
: diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
+ } else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
+ !T->isIncompleteType()) {
+ // Is the array too large?
+ unsigned ActiveSizeBits
+ = ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
+ if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
+ Diag(ArraySize->getLocStart(), diag::err_array_too_large)
+ << ConstVal.toString(10)
+ << ArraySize->getSourceRange();
}
+
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
Added: cfe/trunk/test/Sema/array-size-64.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-size-64.c?rev=111338&view=auto
==============================================================================
--- cfe/trunk/test/Sema/array-size-64.c (added)
+++ cfe/trunk/test/Sema/array-size-64.c Tue Aug 17 19:39:00 2010
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify %s
+
+void f() {
+ int a[2147483647U][2147483647U]; // expected-error{{array is too large}}
+ int b[1073741825U - 1U][2147483647U];
+ int c[18446744073709551615U/sizeof(int)/2];
+}
Propchange: cfe/trunk/test/Sema/array-size-64.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/Sema/array-size-64.c
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/Sema/array-size-64.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/Sema/array-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-size.c?rev=111338&view=auto
==============================================================================
--- cfe/trunk/test/Sema/array-size.c (added)
+++ cfe/trunk/test/Sema/array-size.c Tue Aug 17 19:39:00 2010
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin -verify %s
+
+void f() {
+ int x0[1073741824]; // expected-error{{array is too large}}
+ int x1[1073741824 + 1]; // expected-error{{array is too large}}
+ int x2[(unsigned)1073741824]; // expected-error{{array is too large}}
+ int x3[(unsigned)1073741824 + 1]; // expected-error{{array is too large}}
+ int x4[1073741824 - 1];
+}
+
Propchange: cfe/trunk/test/Sema/array-size.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/Sema/array-size.c
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/Sema/array-size.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list