Skip to content

Commit

Permalink
[sanitizer_common] Fix internal_*stat on Linux/sparc64 (llvm#101012)
Browse files Browse the repository at this point in the history
```
  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`.
  • Loading branch information
rorth authored Jul 30, 2024
1 parent 1c25f2c commit fcd6bd5
Showing 1 changed file with 34 additions and 7 deletions.
41 changes: 34 additions & 7 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -48,6 +52,7 @@
# endif
# include <asm/stat.h>
# undef stat
# undef stat64
# endif

# include <dlfcn.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit fcd6bd5

Please sign in to comment.