Skip to content

Commit fcd6bd5

Browse files
authored
[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`.
1 parent 1c25f2c commit fcd6bd5

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@
3333
// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
3434
// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
3535
// access stat from asm/stat.h, without conflicting with definition in
36-
// sys/stat.h, we use this trick.
37-
# if SANITIZER_MIPS64
36+
// sys/stat.h, we use this trick. sparc64 is similar, using
37+
// syscall(__NR_stat64) and struct kernel_stat64.
38+
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
3839
# include <asm/unistd.h>
3940
# include <sys/types.h>
4041
# define stat kernel_stat
42+
# if SANITIZER_SPARC64
43+
# define stat64 kernel_stat64
44+
# endif
4145
# if SANITIZER_GO
4246
# undef st_atime
4347
# undef st_mtime
@@ -48,6 +52,7 @@
4852
# endif
4953
# include <asm/stat.h>
5054
# undef stat
55+
# undef stat64
5156
# endif
5257

5358
# include <dlfcn.h>
@@ -285,8 +290,7 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
285290
return res;
286291
}
287292

288-
# if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && \
289-
SANITIZER_LINUX
293+
# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
290294
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
291295
internal_memset(out, 0, sizeof(*out));
292296
out->st_dev = in->st_dev;
@@ -327,7 +331,12 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
327331
}
328332
# endif
329333

330-
# if SANITIZER_MIPS64
334+
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
335+
# if SANITIZER_MIPS64
336+
typedef struct kernel_stat kstat_t;
337+
# else
338+
typedef struct kernel_stat64 kstat_t;
339+
# endif
331340
// Undefine compatibility macros from <sys/stat.h>
332341
// so that they would not clash with the kernel_stat
333342
// st_[a|m|c]time fields
@@ -345,7 +354,7 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
345354
# undef st_mtime_nsec
346355
# undef st_ctime_nsec
347356
# endif
348-
static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
357+
static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
349358
internal_memset(out, 0, sizeof(*out));
350359
out->st_dev = in->st_dev;
351360
out->st_ino = in->st_ino;
@@ -391,6 +400,12 @@ uptr internal_stat(const char *path, void *buf) {
391400
!SANITIZER_SPARC
392401
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
393402
0);
403+
# elif SANITIZER_SPARC64
404+
kstat_t buf64;
405+
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
406+
(uptr)&buf64, 0);
407+
kernel_stat_to_stat(&buf64, (struct stat *)buf);
408+
return res;
394409
# else
395410
struct stat64 buf64;
396411
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
@@ -423,6 +438,12 @@ uptr internal_lstat(const char *path, void *buf) {
423438
!SANITIZER_SPARC
424439
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
425440
AT_SYMLINK_NOFOLLOW);
441+
# elif SANITIZER_SPARC64
442+
kstat_t buf64;
443+
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
444+
(uptr)&buf64, AT_SYMLINK_NOFOLLOW);
445+
kernel_stat_to_stat(&buf64, (struct stat *)buf);
446+
return res;
426447
# else
427448
struct stat64 buf64;
428449
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
@@ -442,10 +463,16 @@ uptr internal_fstat(fd_t fd, void *buf) {
442463
# if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
443464
# if SANITIZER_MIPS64
444465
// For mips64, fstat syscall fills buffer in the format of kernel_stat
445-
struct kernel_stat kbuf;
466+
kstat_t kbuf;
446467
int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
447468
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
448469
return res;
470+
# elif SANITIZER_LINUX && SANITIZER_SPARC64
471+
// For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64
472+
kstat_t kbuf;
473+
int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
474+
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
475+
return res;
449476
# elif SANITIZER_LINUX && defined(__loongarch__)
450477
struct statx bufx;
451478
int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,

0 commit comments

Comments
 (0)