diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7700,6 +7700,8 @@ "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup, DefaultIgnore; +def err_overaligned_array_element : Error< + "alignment of array element type %0 is larger than its size">; def err_aligned_allocation_unavailable : Error< "aligned %select{allocation|deallocation}0 function of type '%1' is " "%select{only|not}4 available on %2%select{ %3 or newer|}4">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2439,6 +2439,10 @@ bool isUsualDeallocationFunction(const CXXMethodDecl *FD); + // Determine whether an array element type's alignment is larger than its + // size. + bool isArrayElementOveraligned(QualType EltTy, SourceLocation Loc); + bool isCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind = CompleteTypeKind::Default) { return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2449,6 +2449,8 @@ else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; + else if (isArrayElementOveraligned(AllocType, Loc)) + return true; else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2395,6 +2395,21 @@ return R; } +bool Sema::isArrayElementOveraligned(QualType EltTy, SourceLocation Loc) { + EltTy = Context.getBaseElementType(EltTy); + if (EltTy->isIncompleteType() || EltTy->isDependentType() || + EltTy->isUndeducedType()) + return false; + + CharUnits Size = Context.getTypeSizeInChars(EltTy); + + if (Size.isZero() || Size >= Context.getTypeAlignInChars(EltTy)) + return false; + + Diag(Loc, diag::err_overaligned_array_element) << EltTy; + return true; +} + /// Build an array type. /// /// \param T The type of each element in the array. @@ -2478,6 +2493,9 @@ return QualType(); } + if (isArrayElementOveraligned(T, Loc)) + return QualType(); + // Do placeholder conversions on the array size expression. if (ArraySize && ArraySize->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(ArraySize); diff --git a/clang/test/CodeGenCXX/ubsan-new-checks.cpp b/clang/test/CodeGenCXX/ubsan-new-checks.cpp --- a/clang/test/CodeGenCXX/ubsan-new-checks.cpp +++ b/clang/test/CodeGenCXX/ubsan-new-checks.cpp @@ -18,10 +18,10 @@ S4() : S3() {} }; -typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t; +typedef __attribute__((ext_vector_type(8), aligned(32))) float float32x8_t; struct S5 { - float32x2_t x; + float32x8_t x; }; void *operator new (unsigned long, void *p) { return p; } @@ -54,21 +54,21 @@ return new S2[20]; } -float32x2_t *func_04() { +float32x8_t *func_04() { // CHECK-LABEL: define {{.*}} @_Z7func_04v // CHECK: and i64 %{{.*}}, 31, !nosanitize // CHECK: icmp eq i64 %{{.*}}, 0, !nosanitize - // CHECK: ret <2 x float>* - return new float32x2_t; + // CHECK: ret <8 x float>* + return new float32x8_t; } -float32x2_t *func_05() { +float32x8_t *func_05() { // CHECK-LABEL: define {{.*}} @_Z7func_05v // CHECK: and i64 %{{.*}}, 31, !nosanitize // CHECK: icmp eq i64 %{{.*}}, 0, !nosanitize // CHECK-NOT: and i64 %{{.*}}, 31 - // CHECK: ret <2 x float>* - return new float32x2_t[20]; + // CHECK: ret <8 x float>* + return new float32x8_t[20]; } S3 *func_07() { @@ -110,21 +110,21 @@ return new(p) S2[10]; } -float32x2_t *func_12() { +float32x8_t *func_12() { // CHECK-LABEL: define {{.*}} @_Z7func_12v // CHECK: and i64 %{{.*}}, 31, !nosanitize // CHECK: icmp eq i64 %{{.*}}, 0, !nosanitize - // CHECK: ret <2 x float>* - return new float32x2_t; + // CHECK: ret <8 x float>* + return new float32x8_t; } -float32x2_t *func_13() { +float32x8_t *func_13() { // CHECK-LABEL: define {{.*}} @_Z7func_13v // CHECK: and i64 %{{.*}}, 31, !nosanitize // CHECK: icmp eq i64 %{{.*}}, 0, !nosanitize // CHECK-NOT: and i64 %{{.*}}, 31 - // CHECK: ret <2 x float>* - return new float32x2_t[20]; + // CHECK: ret <8 x float>* + return new float32x8_t[20]; } S4 *func_14() { diff --git a/clang/test/Layout/ms-aligned-array.c b/clang/test/Layout/ms-aligned-array.c --- a/clang/test/Layout/ms-aligned-array.c +++ b/clang/test/Layout/ms-aligned-array.c @@ -6,7 +6,10 @@ // FIXME: What about other type sugar, like _Atomic? This would only matter in a // packed struct context. struct __declspec(align(16)) AlignedStruct { int x; }; -typedef int __declspec(align(16)) AlignedInt; +struct Struct2 { + char c[16]; +}; +typedef struct Struct2 __declspec(align(16)) AlignedStruct2; #define CHECK_SIZE(X, Align) \ _Static_assert(__alignof(struct X) == Align, "should be aligned"); @@ -20,13 +23,13 @@ struct B { char b; - AlignedInt a[1]; + AlignedStruct2 a[1]; }; CHECK_SIZE(B, 16); struct C { char b; - AlignedInt a[]; + AlignedStruct2 a[]; }; CHECK_SIZE(C, 16); @@ -39,14 +42,18 @@ // CHECK-NEXT: 0 | struct AlignedStruct[1] a // CHECK-NEXT: | [sizeof=16, align=16] // CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct Struct2 +// CHECK-NEXT: 0 | char[16] c +// CHECK-NEXT: | [sizeof=16, align=1] +// CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct B // CHECK-NEXT: 0 | char b -// CHECK-NEXT: 16 | AlignedInt[1] a +// CHECK-NEXT: 16 | AlignedStruct2[1] a // CHECK-NEXT: | [sizeof=32, align=16] // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct C // CHECK-NEXT: 0 | char b -// CHECK-NEXT: 16 | AlignedInt[] a +// CHECK-NEXT: 16 | AlignedStruct2[] a // CHECK-NEXT: | [sizeof=16, align=16] #pragma pack(pop) diff --git a/clang/test/Sema/attr-aligned.c b/clang/test/Sema/attr-aligned.c --- a/clang/test/Sema/attr-aligned.c +++ b/clang/test/Sema/attr-aligned.c @@ -49,13 +49,14 @@ char e1[__alignof__(e) == 2 ?: -1] = {0}; char e2[__alignof__(e.member) == 2 ?: -1] = {0}; -typedef char overaligned_char __attribute__((aligned(16))); -typedef overaligned_char array_with_overaligned_char[11]; +typedef struct { char c[16]; } S; +typedef S overaligned_struct __attribute__((aligned(16))); +typedef overaligned_struct array_with_overaligned_struct[11]; typedef char array_with_align_attr[11] __attribute__((aligned(16))); -char f0[__alignof__(array_with_overaligned_char) == 16 ? 1 : -1] = { 0 }; +char f0[__alignof__(array_with_overaligned_struct) == 16 ? 1 : -1] = { 0 }; char f1[__alignof__(array_with_align_attr) == 16 ? 1 : -1] = { 0 }; -array_with_overaligned_char F2; +array_with_overaligned_struct F2; char f2[__alignof__(F2) == 16 ? 1 : -1] = { 0 }; array_with_align_attr F3; char f3[__alignof__(F3) == 16 ? 1 : -1] = { 0 }; diff --git a/clang/test/SemaCXX/array-alignment.cpp b/clang/test/SemaCXX/array-alignment.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/array-alignment.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef char __attribute__((aligned(2))) AlignedChar; +typedef AlignedChar arrayType0[4]; // expected-error {{alignment of array element}} + +typedef struct __attribute__((aligned(8))) { + int m0; +} AlignedStruct; + +AlignedChar a0[1]; // expected-error {{alignment of array element}} +AlignedStruct a1[1]; + +struct S { + AlignedChar m0[1]; // expected-error {{alignment of array element}} + AlignedStruct m1[1]; +}; + +void test(char *p) { + auto p0 = (AlignedChar(*)[1])p; // expected-error {{alignment of array element}} + auto r0 = (AlignedChar(&)[1])(*p); // expected-error {{alignment of array element}} + auto p1 = new AlignedChar[1]; // expected-error {{alignment of array element}} + auto p2 = (AlignedStruct(*)[1])p; + auto p3 = new AlignedStruct[1]; +} diff --git a/clang/test/SemaCXX/warn-new-overaligned.cpp b/clang/test/SemaCXX/warn-new-overaligned.cpp --- a/clang/test/SemaCXX/warn-new-overaligned.cpp +++ b/clang/test/SemaCXX/warn-new-overaligned.cpp @@ -19,9 +19,13 @@ } namespace test2 { +struct S { + char c[256]; +}; + class Test { - typedef int __attribute__((aligned(256))) aligned_int; - aligned_int high_contention_data[10]; + typedef S __attribute__((aligned(256))) alignedS; + alignedS high_contention_data[10]; }; void helper() {