forked from OSchip/llvm-project
[Sema] Reject array element types whose sizes aren't a multiple of their
alignments In the following code, the first element is aligned on a 16-byte boundary, but the remaining elements aren't: ``` typedef char int8_a16 __attribute__((aligned(16))); int8_a16 array[4]; ``` Currently clang doesn't reject the code, but it should since it can cause crashes at runtime. This patch also fixes assertion failures in CodeGen caused by the changes in https://reviews.llvm.org/D123649. Differential Revision: https://reviews.llvm.org/D133711
This commit is contained in:
parent
f47a5df92d
commit
adaf62ced2
|
@ -70,6 +70,8 @@ code bases.
|
|||
results do not change before/after setting
|
||||
``-Werror=incompatible-function-pointer-types`` to avoid incompatibility with
|
||||
Clang 16.
|
||||
- Clang now disallows types whose sizes aren't a multiple of their alignments to
|
||||
be used as the element type of arrays.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
|
|
@ -7703,6 +7703,8 @@ def warn_overaligned_type : Warning<
|
|||
"type %0 requires %1 bytes of alignment and the default allocator only "
|
||||
"guarantees %2 bytes">,
|
||||
InGroup<OveralignedType>, DefaultIgnore;
|
||||
def err_array_element_alignment : Error<
|
||||
"size of array element of type %0 (%1 bytes) isn't a multiple of its alignment (%2 bytes)">;
|
||||
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">;
|
||||
|
|
|
@ -2442,6 +2442,10 @@ public:
|
|||
|
||||
bool isUsualDeallocationFunction(const CXXMethodDecl *FD);
|
||||
|
||||
// Check whether the size of array element of type \p EltTy is a multiple of
|
||||
// its alignment and return false if it isn't.
|
||||
bool checkArrayElementAlignment(QualType EltTy, SourceLocation Loc);
|
||||
|
||||
bool isCompleteType(SourceLocation Loc, QualType T,
|
||||
CompleteTypeKind Kind = CompleteTypeKind::Default) {
|
||||
return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr);
|
||||
|
|
|
@ -2449,6 +2449,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
|
|||
else if (RequireNonAbstractType(Loc, AllocType,
|
||||
diag::err_allocation_of_abstract_type))
|
||||
return true;
|
||||
else if (!checkArrayElementAlignment(AllocType, Loc))
|
||||
return true;
|
||||
else if (AllocType->isVariablyModifiedType())
|
||||
return Diag(Loc, diag::err_variably_modified_new_type)
|
||||
<< AllocType;
|
||||
|
|
|
@ -2394,6 +2394,23 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
|
|||
return R;
|
||||
}
|
||||
|
||||
bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) {
|
||||
EltTy = Context.getBaseElementType(EltTy);
|
||||
if (EltTy->isIncompleteType() || EltTy->isDependentType() ||
|
||||
EltTy->isUndeducedType())
|
||||
return true;
|
||||
|
||||
CharUnits Size = Context.getTypeSizeInChars(EltTy);
|
||||
CharUnits Alignment = Context.getTypeAlignInChars(EltTy);
|
||||
|
||||
if (Size.isMultipleOf(Alignment))
|
||||
return true;
|
||||
|
||||
Diag(Loc, diag::err_array_element_alignment)
|
||||
<< EltTy << Size.getQuantity() << Alignment.getQuantity();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Build an array type.
|
||||
///
|
||||
/// \param T The type of each element in the array.
|
||||
|
@ -2477,6 +2494,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
|
|||
return QualType();
|
||||
}
|
||||
|
||||
if (!checkArrayElementAlignment(T, Loc))
|
||||
return QualType();
|
||||
|
||||
// Do placeholder conversions on the array size expression.
|
||||
if (ArraySize && ArraySize->hasPlaceholderType()) {
|
||||
ExprResult Result = CheckPlaceholderExpr(ArraySize);
|
||||
|
|
|
@ -35,6 +35,6 @@ class D : virtual B<0>, virtual B<1> {
|
|||
//#pragma pack(pop)
|
||||
|
||||
void use_structs() {
|
||||
C cs[sizeof(C)];
|
||||
D ds[sizeof(D)];
|
||||
C cs;
|
||||
D ds;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ struct S4 : public S3 {
|
|||
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 @@ S2 *func_03() {
|
|||
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 @@ S2 *func_11(void *p) {
|
|||
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() {
|
||||
|
|
|
@ -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 @@ CHECK_SIZE(A, 16);
|
|||
|
||||
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_SIZE(C, 16);
|
|||
// 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)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>&1 \
|
||||
// RUN: | FileCheck %s
|
||||
// RUN: %clang_cc1 -fno-rtti -triple i686-pc-win32 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>/dev/null \
|
||||
// RUN: | FileCheck %s -check-prefix CHECK-X64
|
||||
|
||||
|
@ -7,14 +6,10 @@ struct T0 { char c; };
|
|||
struct T2 : virtual T0 { };
|
||||
struct T3 { T2 a[1]; char c; };
|
||||
|
||||
// CHECK: *** Dumping AST Record Layout
|
||||
// CHECK: *** Dumping AST Record Layout
|
||||
// CHECK: *** Dumping AST Record Layout
|
||||
// CHECK-NEXT: 0 | struct T3
|
||||
// CHECK-NEXT: 0 | T2[1] a
|
||||
// CHECK-NEXT: 5 | char c
|
||||
// CHECK-NEXT: | [sizeof=8, align=4
|
||||
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
||||
#ifdef _ILP32
|
||||
// expected-error@-3 {{size of array element}}
|
||||
#endif
|
||||
|
||||
// CHECK-X64: *** Dumping AST Record Layout
|
||||
// CHECK-X64: *** Dumping AST Record Layout
|
||||
// CHECK-X64: *** Dumping AST Record Layout
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
// PR5637
|
||||
|
||||
|
@ -7,7 +6,7 @@ typedef __attribute__((aligned(16))) struct {
|
|||
unsigned long long w[3];
|
||||
} UINT192;
|
||||
|
||||
UINT192 ten2mk192M[] = {
|
||||
UINT192 ten2mk192M[] = { // expected-error {{size of array element}}
|
||||
{{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}},
|
||||
{{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}},
|
||||
{{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c11 -triple i386-apple-darwin9 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
|
||||
|
||||
|
@ -38,10 +37,10 @@ typedef ALIGNED(2) struct {
|
|||
} aligned_before_struct;
|
||||
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct) == 3);
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[1]) == 4);
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[2]) == 6);
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[2][1]) == 8);
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[1][2]) == 6);
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[1]) == 4); // expected-error {{size of array element}}
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[2]) == 6); // expected-error {{size of array element}}
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[2][1]) == 8); // expected-error {{size of array element}}
|
||||
STATIC_ASSERT(sizeof(aligned_before_struct[1][2]) == 6); // expected-error {{size of array element}}
|
||||
|
||||
typedef struct ALIGNED(2) {
|
||||
char a[3];
|
||||
|
|
|
@ -49,13 +49,14 @@ struct E e;
|
|||
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 };
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -triple i386-apple-darwin9 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
using size_t = decltype(sizeof(0));
|
||||
|
||||
|
@ -46,10 +45,10 @@ typedef ALIGNED(2) struct {
|
|||
} aligned_before_struct;
|
||||
|
||||
static_assert(sizeof(aligned_before_struct) == 3, "");
|
||||
static_assert(sizeof(aligned_before_struct[1]) == 4, "");
|
||||
static_assert(sizeof(aligned_before_struct[2]) == 6, "");
|
||||
static_assert(sizeof(aligned_before_struct[2][1]) == 8, "");
|
||||
static_assert(sizeof(aligned_before_struct[1][2]) == 6, "");
|
||||
static_assert(sizeof(aligned_before_struct[1]) == 4, ""); // expected-error {{size of array element}}
|
||||
static_assert(sizeof(aligned_before_struct[2]) == 6, ""); // expected-error {{size of array element}}
|
||||
static_assert(sizeof(aligned_before_struct[2][1]) == 8, ""); // expected-error {{size of array element}}
|
||||
static_assert(sizeof(aligned_before_struct[1][2]) == 6, ""); // expected-error {{size of array element}}
|
||||
|
||||
typedef struct ALIGNED(2) {
|
||||
char a[3];
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
typedef char __attribute__((aligned(2))) AlignedChar;
|
||||
typedef AlignedChar arrayType0[4]; // expected-error {{size of array element}}
|
||||
|
||||
struct __attribute__((aligned(8))) AlignedStruct {
|
||||
int m0;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) PackedStruct {
|
||||
char m0;
|
||||
int i0;
|
||||
};
|
||||
|
||||
typedef PackedStruct AlignedPackedStruct __attribute__((aligned(4)));
|
||||
typedef AlignedPackedStruct arrayType1[4]; // expected-error {{(5 bytes) isn't a multiple of its alignment (4 bytes)}}
|
||||
|
||||
AlignedChar a0[1]; // expected-error {{size of array element}}
|
||||
AlignedStruct a1[1];
|
||||
AlignedPackedStruct a2[1]; // expected-error {{size of array element}}
|
||||
|
||||
struct S {
|
||||
AlignedChar m0[1]; // expected-error {{size of array element}}
|
||||
AlignedStruct m1[1];
|
||||
AlignedPackedStruct m2[1]; // expected-error {{size of array element}}
|
||||
};
|
||||
|
||||
void test(char *p) {
|
||||
auto p0 = (AlignedChar(*)[1])p; // expected-error {{size of array element}}
|
||||
auto r0 = (AlignedChar(&)[1])(*p); // expected-error {{size of array element}}
|
||||
auto p1 = new AlignedChar[1]; // expected-error {{size of array element}}
|
||||
auto p2 = (AlignedStruct(*)[1])p;
|
||||
auto p3 = new AlignedStruct[1];
|
||||
auto p4 = (AlignedPackedStruct(*)[1])p; // expected-error {{size of array element}}
|
||||
auto p5 = new AlignedPackedStruct[1]; // expected-error {{size of array element}}
|
||||
}
|
|
@ -19,9 +19,13 @@ void helper() {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue