about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/tst-getdents64.c
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-11-16 16:52:36 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2021-01-22 15:44:41 -0300
commit42d6270439e06138832b54e2fb6c5e38d7690814 (patch)
tree92a76e6365b98ce95a4d5fe1202faf484b998ecf /sysdeps/unix/sysv/linux/tst-getdents64.c
parent5f478eb0fb2b22204d501b6721c6fe9dc1f3ebba (diff)
downloadglibc-42d6270439e06138832b54e2fb6c5e38d7690814.tar.gz
glibc-42d6270439e06138832b54e2fb6c5e38d7690814.tar.xz
glibc-42d6270439e06138832b54e2fb6c5e38d7690814.zip
linux: mips: Fix getdents64 fallback on mips64-n32
GCC mainline shows the following error:

../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c: In function '__getdents64':
../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c:121:7: error: 'memcpy' forming offset [4, 7] is out of the bounds [0, 4] [-Werror=array-bounds]
  121 |       memcpy (((char *) dp + offsetof (struct dirent64, d_ino)),
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |               KDP_MEMBER (kdp, d_ino), sizeof ((struct dirent64){0}.d_ino));
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c:123:7: error: 'memcpy' forming offset [4, 7] is out of the bounds [0, 4] [-Werror=array-bounds]
  123 |       memcpy (((char *) dp + offsetof (struct dirent64, d_off)),
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  124 |               KDP_MEMBER (kdp, d_off), sizeof ((struct dirent64){0}.d_off));
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The issue is due both d_ino and d_off fields for mips64-n32
kernel_dirent are 32-bits, while this is using memcpy to copy 64 bits
from it into the glibc dirent64.

The fix is to use a temporary buffer to read the correct type
from kernel_dirent.

Checked with a build-many-glibcs.py for mips64el-linux-gnu and I
also checked the tst-getdents64 on mips64el 4.1.4 kernel with
and without fallback enabled (by manually setting the
getdents64_supported).
Diffstat (limited to 'sysdeps/unix/sysv/linux/tst-getdents64.c')
-rw-r--r--sysdeps/unix/sysv/linux/tst-getdents64.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/sysdeps/unix/sysv/linux/tst-getdents64.c b/sysdeps/unix/sysv/linux/tst-getdents64.c
index 379ecbbcc6..691444d56e 100644
--- a/sysdeps/unix/sysv/linux/tst-getdents64.c
+++ b/sysdeps/unix/sysv/linux/tst-getdents64.c
@@ -76,8 +76,18 @@ large_buffer_checks (int fd)
     }
 }
 
-static int
-do_test (void)
+static void
+do_test_large_size (void)
+{
+  int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
+  TEST_VERIFY (fd >= 0);
+  large_buffer_checks (fd);
+
+  xclose (fd);
+}
+
+static void
+do_test_by_size (size_t buffer_size)
 {
   /* The test compares the iteration order with readdir64.  */
   DIR *reference = opendir (".");
@@ -98,7 +108,7 @@ do_test (void)
              non-existing data.  */
           struct
           {
-            char buffer[1024];
+            char buffer[buffer_size];
             struct dirent64 pad;
           } data;
 
@@ -153,10 +163,19 @@ do_test (void)
       rewinddir (reference);
     }
 
-  large_buffer_checks (fd);
-
   xclose (fd);
   closedir (reference);
+}
+
+static int
+do_test (void)
+{
+  do_test_by_size (512);
+  do_test_by_size (1024);
+  do_test_by_size (4096);
+
+  do_test_large_size ();
+
   return 0;
 }