[llvm-branch-commits] [compiler-rt] [sanitizer_common] Fix internal_*stat on Linux/sparc64 (PR #101236)

Rainer Orth via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jul 30 13:35:08 PDT 2024


https://github.com/rorth created https://github.com/llvm/llvm-project/pull/101236

Backport of fcd6bd5587cc376cd8f43b60d1c7d61fdfe0f535 and 16e9bb9cd7f50ae2ec7f29a80bc3b95f528bfdbf to `release/19.x` branch.

>From 7d97041c217bcb4b04cacb3a5d17285f8b241a88 Mon Sep 17 00:00:00 2001
From: Rainer Orth <ro at gcc.gnu.org>
Date: Tue, 30 Jul 2024 09:03:00 +0200
Subject: [PATCH 1/2] [sanitizer_common] Fix internal_*stat on Linux/sparc64
 (#101012)

```
  SanitizerCommon-Unit :: ./Sanitizer-sparcv9-Test/SanitizerCommon/FileOps
```
`FAIL`s on 64-bit Linux/sparc64:
```
projects/compiler-rt/lib/sanitizer_common/tests/./Sanitizer-sparcv9-Test --gtest_filter=SanitizerCommon.FileOps
--
compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp:144: Failure
Expected equality of these values:
  len1 + len2
    Which is: 10
  fsize
    Which is: 1721875535
```
The issue is similar to the mips64 case: the Linux/sparc64 `*stat`
syscalls take a `struct kernel_stat64 *` arg. Also the syscalls actually
used differ.

This patch handles this, adopting the mips64 code to avoid too much
duplication.

Tested on `sparc64-unknown-linux-gnu` and `x86_64-pc-linux-gnu`.

(cherry picked from commit fcd6bd5587cc376cd8f43b60d1c7d61fdfe0f535)
---
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 41 +++++++++++++++----
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 76acf591871ab..09f58b7ced2e9 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -33,11 +33,15 @@
 // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
 // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
 // access stat from asm/stat.h, without conflicting with definition in
-// sys/stat.h, we use this trick.
-#  if SANITIZER_MIPS64
+// sys/stat.h, we use this trick.  sparc64 is similar, using
+// syscall(__NR_stat64) and struct kernel_stat64.
+#  if SANITIZER_MIPS64 || SANITIZER_SPARC64
 #    include <asm/unistd.h>
 #    include <sys/types.h>
 #    define stat kernel_stat
+#    if SANITIZER_SPARC64
+#      define stat64 kernel_stat64
+#    endif
 #    if SANITIZER_GO
 #      undef st_atime
 #      undef st_mtime
@@ -48,6 +52,7 @@
 #    endif
 #    include <asm/stat.h>
 #    undef stat
+#    undef stat64
 #  endif
 
 #  include <dlfcn.h>
@@ -285,8 +290,7 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
   return res;
 }
 
-#    if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && \
-        SANITIZER_LINUX
+#    if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
 static void stat64_to_stat(struct stat64 *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
@@ -327,7 +331,12 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
 }
 #    endif
 
-#    if SANITIZER_MIPS64
+#    if SANITIZER_MIPS64 || SANITIZER_SPARC64
+#      if SANITIZER_MIPS64
+typedef struct kernel_stat kstat_t;
+#      else
+typedef struct kernel_stat64 kstat_t;
+#      endif
 // Undefine compatibility macros from <sys/stat.h>
 // so that they would not clash with the kernel_stat
 // st_[a|m|c]time fields
@@ -345,7 +354,7 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
 #        undef st_mtime_nsec
 #        undef st_ctime_nsec
 #      endif
-static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
+static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
   out->st_ino = in->st_ino;
@@ -391,6 +400,12 @@ uptr internal_stat(const char *path, void *buf) {
           !SANITIZER_SPARC
   return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           0);
+#      elif SANITIZER_SPARC64
+  kstat_t buf64;
+  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
+                             (uptr)&buf64, 0);
+  kernel_stat_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #      else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
@@ -423,6 +438,12 @@ uptr internal_lstat(const char *path, void *buf) {
           !SANITIZER_SPARC
   return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           AT_SYMLINK_NOFOLLOW);
+#      elif SANITIZER_SPARC64
+  kstat_t buf64;
+  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
+                             (uptr)&buf64, AT_SYMLINK_NOFOLLOW);
+  kernel_stat_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #      else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
@@ -442,10 +463,16 @@ uptr internal_fstat(fd_t fd, void *buf) {
 #    if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
 #      if SANITIZER_MIPS64
   // For mips64, fstat syscall fills buffer in the format of kernel_stat
-  struct kernel_stat kbuf;
+  kstat_t kbuf;
   int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
   kernel_stat_to_stat(&kbuf, (struct stat *)buf);
   return res;
+#      elif SANITIZER_LINUX && SANITIZER_SPARC64
+  // For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64
+  kstat_t kbuf;
+  int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
+  kernel_stat_to_stat(&kbuf, (struct stat *)buf);
+  return res;
 #      elif SANITIZER_LINUX && defined(__loongarch__)
   struct statx bufx;
   int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,

>From 079c97a91b3b134c746d1aa02db90ef3357998d6 Mon Sep 17 00:00:00 2001
From: Rainer Orth <ro at gcc.gnu.org>
Date: Tue, 30 Jul 2024 10:06:45 +0200
Subject: [PATCH 2/2] [sanitizer_common] Make sanitizer_linux.cpp kernel_stat*
 handling Linux-specific

fcd6bd5587cc376cd8f43b60d1c7d61fdfe0f535 broke the Solaris/sparcv9 buildbot:
```
compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp:39:14: fatal error: 'asm/unistd.h' file not found
   39 | #    include <asm/unistd.h>
      |              ^~~~~~~~~~~~~~
```
That section should have been Linux-specific in the first place, which is
what this patch does.

Tested on sparcv9-sun-solaris2.11.

(cherry picked from commit 16e9bb9cd7f50ae2ec7f29a80bc3b95f528bfdbf)
---
 compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 09f58b7ced2e9..d1c50cbda7d7e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -35,7 +35,7 @@
 // access stat from asm/stat.h, without conflicting with definition in
 // sys/stat.h, we use this trick.  sparc64 is similar, using
 // syscall(__NR_stat64) and struct kernel_stat64.
-#  if SANITIZER_MIPS64 || SANITIZER_SPARC64
+#  if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64)
 #    include <asm/unistd.h>
 #    include <sys/types.h>
 #    define stat kernel_stat



More information about the llvm-branch-commits mailing list