Skip to content

Commit 5916903

Browse files
authored
[clang] Fix crash when #embed data does not fit into an array (#129567)
Tune SemaInit code handling #embed to take into account how many array elements remains to initialize. Also issue a warning/error message when the array/struct is at the end but there is still #embed data left. Fixes #128987
1 parent 5c375c3 commit 5916903

File tree

4 files changed

+111
-2
lines changed

4 files changed

+111
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ Bug Fixes in This Version
243243
when it can affect template argument deduction (#GH122306).
244244
- Fix crash on code completion of function calls involving partial order of function templates
245245
(#GH125500).
246+
- Fixed clang crash when #embed data does not fit into an array
247+
(#GH128987).
246248

247249
Bug Fixes to Compiler Builtins
248250
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaInit.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,13 @@ class InitListChecker {
519519
uint64_t ElsCount = 1;
520520
// Otherwise try to fill whole array with embed data.
521521
if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
522+
unsigned ArrIndex = Entity.getElementIndex();
522523
auto *AType =
523524
SemaRef.Context.getAsArrayType(Entity.getParent()->getType());
524525
assert(AType && "expected array type when initializing array");
525526
ElsCount = Embed->getDataElementCount();
526527
if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
527-
ElsCount = std::min(CAType->getSize().getZExtValue(),
528+
ElsCount = std::min(CAType->getSize().getZExtValue() - ArrIndex,
528529
ElsCount - CurEmbedIndex);
529530
if (ElsCount == Embed->getDataElementCount()) {
530531
CurEmbed = nullptr;
@@ -1317,7 +1318,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
13171318
return;
13181319

13191320
// Don't complain for incomplete types, since we'll get an error elsewhere.
1320-
if (Index < IList->getNumInits() && !T->isIncompleteType()) {
1321+
if ((Index < IList->getNumInits() || CurEmbed) && !T->isIncompleteType()) {
13211322
// We have leftover initializers
13221323
bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
13231324
(SemaRef.getLangOpts().OpenCL && T->isVectorType());
@@ -2180,6 +2181,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
21802181

21812182
InitializedEntity ElementEntity = InitializedEntity::InitializeElement(
21822183
SemaRef.Context, StructuredIndex, Entity);
2184+
ElementEntity.setElementIndex(elementIndex.getExtValue());
21832185

21842186
unsigned EmbedElementIndexBeforeInit = CurEmbedIndex;
21852187
// Check this element.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %clang_cc1 -std=c23 -emit-llvm -triple x86_64 %s -o - | FileCheck %s
2+
3+
struct S {
4+
int arr[3];
5+
};
6+
7+
struct S1 {
8+
struct S s;
9+
};
10+
11+
// CHECK: @[[BConst:.*]] = private unnamed_addr constant [2 x i32] [i32 47, i32 47]
12+
// CHECK: @[[DConst:.*]] = private unnamed_addr constant [2 x i8] c"//"
13+
// CHECK: @[[SConst:.*]] = private unnamed_addr constant %struct.S { [3 x i32] [i32 47, i32 47, i32 32] }
14+
// CHECK: @[[S1Const:.*]] = private unnamed_addr constant %struct.S1 { %struct.S { [3 x i32] [i32 47, i32 47, i32 32] } }
15+
16+
void cases(int x) {
17+
int a[3] = {x, x,
18+
#embed __FILE__
19+
};
20+
21+
int b[2] = {
22+
#embed __FILE__
23+
};
24+
25+
char d[2] = {
26+
#embed __FILE__
27+
};
28+
29+
struct S s = {
30+
#embed __FILE__
31+
, x
32+
};
33+
34+
struct S1 s1 = {
35+
#embed __FILE__
36+
, x
37+
};
38+
}
39+
// CHECK: define dso_local void @cases(i32 noundef %[[X:.*]])
40+
// CHECK: %[[A:.*]] = alloca [3 x i32]
41+
// CHECK: %[[B:.*]] = alloca [2 x i32]
42+
// CHECK: %[[D:.*]] = alloca [2 x i8]
43+
// CHECK: %[[S:.*]] = alloca %struct.S
44+
// CHECK: %[[S1:.*]] = alloca %struct.S1
45+
// CHECK: %[[LX:.*]] = load i32, ptr %[[X]].addr
46+
// CHECK: store i32 %[[LX]], ptr %[[A]]
47+
// CHECK: %[[GEP1:.*]] = getelementptr inbounds i32, ptr %[[A]], i64 1
48+
// CHECK: %[[LX1:.*]] = load i32, ptr %[[X]].addr
49+
// CHECK: store i32 %1, ptr %arrayinit.element
50+
// CHECK: %[[GEP1:.*]] = getelementptr inbounds i32, ptr %[[A]], i64 2
51+
// CHECK: store i32 47, ptr %[[GEP1]]
52+
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[B]], ptr align 4 @[[BConst]], i64 8, i1 false)
53+
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[D]], ptr align 1 @[[DConst]], i64 2, i1 false)
54+
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[S]], ptr align 4 @[[SConst]], i64 12, i1 false)
55+
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[S1]], ptr align 4 @[[S1Const]], i64 12, i1 false)

clang/test/Sema/excess-embed-data.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=c %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -x c++ -Wno-c23-extensions %s
3+
4+
5+
struct S {
6+
int arr[3];
7+
};
8+
9+
struct S1 {
10+
struct S s;
11+
};
12+
13+
void cases(int x) {
14+
int a[8] = {x, x, x, x, x, x,
15+
#embed __FILE__
16+
// c-warning@-1{{excess elements in array initializer}}
17+
// cpp-error@-2{{excess elements in array initializer}}
18+
};
19+
int b[8] = {
20+
#embed __FILE__
21+
// c-warning@-1{{excess elements in array initializer}}
22+
// cpp-error@-2{{excess elements in array initializer}}
23+
};
24+
int c[3000] = {x, x, x, x, x, x,
25+
#embed __FILE__
26+
};
27+
char d[3] = {
28+
#embed __FILE__
29+
// c-warning@-1{{initializer-string for char array is too long}}
30+
// cpp-error@-2{{initializer-string for char array is too long}}
31+
};
32+
33+
char e[3000] = { 1,
34+
#embed __FILE__
35+
};
36+
37+
struct S s = {
38+
#embed __FILE__
39+
// c-warning@-1{{excess elements in struct initializer}}
40+
// cpp-error@-2{{excess elements in struct initializer}}
41+
, x
42+
};
43+
44+
struct S1 s1 = {
45+
#embed __FILE__
46+
// c-warning@-1{{excess elements in struct initializer}}
47+
// cpp-error@-2{{excess elements in struct initializer}}
48+
, x
49+
};
50+
}

0 commit comments

Comments
 (0)