From 52daccd82cd71bd065826784ebb6eb04fa9b42af Mon Sep 17 00:00:00 2001
From: Jonathan Wakely <jwakely@redhat.com>
Date: Tue, 22 Nov 2022 19:15:53 +0000
Subject: [PATCH 307/547] libstdc++: Fix unsafe use of dirent::d_name
 [PR107814]

Copy the fix for PR 104731 to the equivalent experimental::filesystem
test.

libstdc++-v3/ChangeLog:

	PR libstdc++/107814
	* testsuite/experimental/filesystem/iterators/error_reporting.cc:
	Use a static buffer with space after it.

(cherry picked from commit 1cac00d013856fea4cee0f13c4959c8e21afd2d9)
---
 .../filesystem/iterators/error_reporting.cc   | 35 ++++++++++++-------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc b/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc
index f005b7d5293..aabed14679c 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc
@@ -29,35 +29,44 @@
 
 int choice;
 
-struct dirent global_dirent;
-
 extern "C" struct dirent* readdir(DIR*)
 {
+  // On some targets dirent::d_name is very small, but the OS allocates
+  // a trailing char array after the dirent struct. Emulate that here.
+  union State
+  {
+    struct dirent d;
+    char buf[sizeof(struct dirent) + 16] = {};
+  };
+
+  static State state;
+  char* d_name = state.buf + offsetof(struct dirent, d_name);
+
   switch (choice)
   {
   case 1:
-    global_dirent.d_ino = 999;
+    state.d.d_ino = 999;
 #if defined _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE && defined DT_REG
-    global_dirent.d_type = DT_REG;
+    state.d.d_type = DT_REG;
 #endif
-    global_dirent.d_reclen = 0;
-    std::char_traits<char>::copy(global_dirent.d_name, "file", 5);
+    state.d.d_reclen = 0;
+    std::char_traits<char>::copy(d_name, "file", 5);
     choice = 0;
-    return &global_dirent;
+    return &state.d;
   case 2:
-    global_dirent.d_ino = 111;
+    state.d.d_ino = 111;
 #if defined _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE && defined DT_DIR
-    global_dirent.d_type = DT_DIR;
+    state.d.d_type = DT_DIR;
 #endif
-    global_dirent.d_reclen = 60;
-    std::char_traits<char>::copy(global_dirent.d_name, "subdir", 7);
+    state.d.d_reclen = 60;
+    std::char_traits<char>::copy(d_name, "subdir", 7);
     choice = 1;
-    return &global_dirent;
+    return &state.d;
   default:
     errno = EIO;
     return nullptr;
   }
-  return &global_dirent;
+  return &state.d;
 }
 
 void
-- 
2.25.1

