Skip to content

[clang] Fix crash when #embed data does not fit into an array #129567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 5, 2025

Conversation

Fznamznon
Copy link
Contributor

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

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 llvm#128987
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 3, 2025

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/129567.diff

3 Files Affected:

  • (modified) clang/lib/Sema/SemaInit.cpp (+4-2)
  • (added) clang/test/CodeGen/excess-embed-data.c (+55)
  • (added) clang/test/Sema/excess-embed-data.c (+50)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 86f5a5c1d4434..56ec33fe37bf3 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -519,12 +519,13 @@ class InitListChecker {
     uint64_t ElsCount = 1;
     // Otherwise try to fill whole array with embed data.
     if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
+      unsigned ArrIndex = Entity.getElementIndex();
       auto *AType =
           SemaRef.Context.getAsArrayType(Entity.getParent()->getType());
       assert(AType && "expected array type when initializing array");
       ElsCount = Embed->getDataElementCount();
       if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
-        ElsCount = std::min(CAType->getSize().getZExtValue(),
+        ElsCount = std::min(CAType->getSize().getZExtValue() - ArrIndex,
                             ElsCount - CurEmbedIndex);
       if (ElsCount == Embed->getDataElementCount()) {
         CurEmbed = nullptr;
@@ -1317,7 +1318,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
     return;
 
   // Don't complain for incomplete types, since we'll get an error elsewhere.
-  if (Index < IList->getNumInits() && !T->isIncompleteType()) {
+  if ((Index < IList->getNumInits() || CurEmbed) && !T->isIncompleteType()) {
     // We have leftover initializers
     bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
           (SemaRef.getLangOpts().OpenCL && T->isVectorType());
@@ -2180,6 +2181,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
 
     InitializedEntity ElementEntity = InitializedEntity::InitializeElement(
         SemaRef.Context, StructuredIndex, Entity);
+    ElementEntity.setElementIndex(elementIndex.getExtValue());
 
     unsigned EmbedElementIndexBeforeInit = CurEmbedIndex;
     // Check this element.
diff --git a/clang/test/CodeGen/excess-embed-data.c b/clang/test/CodeGen/excess-embed-data.c
new file mode 100644
index 0000000000000..4303cd80b8c5c
--- /dev/null
+++ b/clang/test/CodeGen/excess-embed-data.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c23 -emit-llvm %s -o - | FileCheck %s
+
+struct S {
+  int arr[3];
+};
+
+struct S1 {
+  struct S s;
+};
+
+// CHECK: @[[BConst:.*]] = private unnamed_addr constant [2 x i32] [i32 47, i32 47]
+// CHECK: @[[DConst:.*]] = private unnamed_addr constant [2 x i8] c"//"
+// CHECK: @[[SConst:.*]] = private unnamed_addr constant %struct.S { [3 x i32] [i32 47, i32 47, i32 32] }
+// CHECK: @[[S1Const:.*]] = private unnamed_addr constant %struct.S1 { %struct.S { [3 x i32] [i32 47, i32 47, i32 32] } }
+
+void cases(int x) {
+  int a[3] = {x, x,
+#embed __FILE__
+  };
+
+  int b[2] = {
+#embed __FILE__
+  };
+
+  char d[2] = {
+#embed __FILE__
+  };
+
+  struct S s = {
+#embed __FILE__
+  , x
+  };
+
+  struct S1 s1 = {
+#embed __FILE__
+  , x
+  };
+}
+// CHECK: define dso_local void @cases(i32 noundef %[[X:.*]])
+// CHECK:  %[[A:.*]] = alloca [3 x i32]
+// CHECK:  %[[B:.*]] = alloca [2 x i32]
+// CHECK:  %[[D:.*]] = alloca [2 x i8]
+// CHECK:  %[[S:.*]] = alloca %struct.S
+// CHECK:  %[[S1:.*]] = alloca %struct.S1
+// CHECK:  %[[LX:.*]] = load i32, ptr %[[X]].addr
+// CHECK:  store i32 %[[LX]], ptr %[[A]]
+// CHECK:  %[[GEP1:.*]] = getelementptr inbounds i32, ptr %[[A]], i64 1
+// CHECK:  %[[LX1:.*]] = load i32, ptr %[[X]].addr
+// CHECK:  store i32 %1, ptr %arrayinit.element
+// CHECK:  %[[GEP1:.*]] = getelementptr inbounds i32, ptr %[[A]], i64 2
+// CHECK:  store i32 47, ptr %[[GEP1]]
+// CHECK:  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[B]], ptr align 4 @[[BConst]], i64 8, i1 false)
+// CHECK:  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[D]], ptr align 1 @[[DConst]], i64 2, i1 false)
+// CHECK:  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[S]], ptr align 4 @[[SConst]], i64 12, i1 false)
+// CHECK:  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[S1]], ptr align 4 @[[S1Const]], i64 12, i1 false)
diff --git a/clang/test/Sema/excess-embed-data.c b/clang/test/Sema/excess-embed-data.c
new file mode 100644
index 0000000000000..d5b84921abc89
--- /dev/null
+++ b/clang/test/Sema/excess-embed-data.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=c %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cpp -x c++ -Wno-c23-extensions %s
+
+
+struct S {
+  int arr[3];
+};
+
+struct S1 {
+  struct S s;
+};
+
+void cases(int x) {
+  int a[8] = {x, x, x, x, x, x,
+#embed __FILE__
+    // c-warning@-1{{excess elements in array initializer}}
+    // cpp-error@-2{{excess elements in array initializer}}
+};
+  int b[8] = {
+#embed __FILE__
+    // c-warning@-1{{excess elements in array initializer}}
+    // cpp-error@-2{{excess elements in array initializer}}
+};
+  int c[3000] = {x, x, x, x, x, x,
+#embed __FILE__
+  };
+ char d[3] = {
+#embed __FILE__
+    // c-warning@-1{{initializer-string for char array is too long}}
+    // cpp-error@-2{{initializer-string for char array is too long}}
+  };
+
+char e[3000] = { 1,
+#embed __FILE__
+};
+
+struct S s = {
+#embed __FILE__
+    // c-warning@-1{{excess elements in struct initializer}}
+    // cpp-error@-2{{excess elements in struct initializer}}
+  , x
+};
+
+struct S1 s1 = {
+#embed __FILE__
+    // c-warning@-1{{excess elements in struct initializer}}
+    // cpp-error@-2{{excess elements in struct initializer}}
+  , x
+};
+}

@cor3ntin
Copy link
Contributor

cor3ntin commented Mar 5, 2025

Thanks for the fix!

@Fznamznon Fznamznon merged commit 5916903 into llvm:main Mar 5, 2025
12 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 5, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime running on omp-vega20-0 while building clang at step 7 "Add check check-offload".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/30/builds/16950

Here is the relevant piece of the build log for the reference
Step 7 (Add check check-offload) failure: test (failure)
...
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/test_libc.cpp (1002 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/wtime.c (1003 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/bug49779.cpp (1004 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/bug50022.cpp (1005 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu :: offloading/std_complex_arithmetic.cpp (1006 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu :: offloading/bug49021.cpp (1007 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/complex_reduction.cpp (1008 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/bug49021.cpp (1009 of 1011)
PASS: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/std_complex_arithmetic.cpp (1010 of 1011)
TIMEOUT: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_offloading_map.cpp (1011 of 1011)
******************** TEST 'libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_offloading_map.cpp' FAILED ********************
Exit Code: -9
Timeout: Reached timeout of 100 seconds

Command Output (stdout):
--
# RUN: at line 1
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp    -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib  -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/parallel_offloading_map.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/parallel_offloading_map.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a && /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/parallel_offloading_map.cpp.tmp | /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/parallel_offloading_map.cpp
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/parallel_offloading_map.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/parallel_offloading_map.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a
# note: command had no output on stdout or stderr
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/parallel_offloading_map.cpp.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -9
# error: command reached timeout: True
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/parallel_offloading_map.cpp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -9
# error: command reached timeout: True

--

********************
Slowest Tests:
--------------------------------------------------------------------------
100.06s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_offloading_map.cpp
16.47s: libomptarget :: amdgcn-amd-amdhsa :: offloading/bug49021.cpp
13.03s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_target_teams_reduction_min.cpp
11.63s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_target_teams_reduction_max.cpp
10.24s: libomptarget :: amdgcn-amd-amdhsa :: offloading/complex_reduction.cpp
9.84s: libomptarget :: amdgcn-amd-amdhsa :: jit/empty_kernel_lvl2.c
9.36s: libomptarget :: x86_64-unknown-linux-gnu :: offloading/bug49021.cpp
7.88s: libomptarget :: x86_64-unknown-linux-gnu :: offloading/std_complex_arithmetic.cpp
7.47s: libomptarget :: amdgcn-amd-amdhsa :: offloading/ompx_saxpy_mixed.c
7.43s: libomptarget :: amdgcn-amd-amdhsa :: offloading/barrier_fence.c
7.16s: libomptarget :: x86_64-unknown-linux-gnu :: offloading/complex_reduction.cpp
6.85s: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/bug49021.cpp
6.28s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_target_teams_reduction.cpp
5.38s: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/std_complex_arithmetic.cpp
5.20s: libomptarget :: x86_64-unknown-linux-gnu-LTO :: offloading/complex_reduction.cpp

jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
…29567)

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 llvm#128987
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Buffer overflow with excess array initializers in #embed
4 participants