diff options
Diffstat (limited to 'test/msan/Linux')
| -rw-r--r-- | test/msan/Linux/getresid.cc | 25 | ||||
| -rw-r--r-- | test/msan/Linux/glob.cc | 27 | ||||
| -rw-r--r-- | test/msan/Linux/glob_altdirfunc.cc | 78 | ||||
| -rw-r--r-- | test/msan/Linux/glob_nomatch.cc | 21 | ||||
| -rw-r--r-- | test/msan/Linux/glob_test_root/aa | 0 | ||||
| -rw-r--r-- | test/msan/Linux/glob_test_root/ab | 0 | ||||
| -rw-r--r-- | test/msan/Linux/glob_test_root/ba | 0 | ||||
| -rw-r--r-- | test/msan/Linux/lit.local.cfg | 9 | ||||
| -rw-r--r-- | test/msan/Linux/sunrpc.cc | 40 | ||||
| -rw-r--r-- | test/msan/Linux/sunrpc_bytes.cc | 38 | ||||
| -rw-r--r-- | test/msan/Linux/sunrpc_string.cc | 35 | ||||
| -rw-r--r-- | test/msan/Linux/syscalls.cc | 115 | ||||
| -rw-r--r-- | test/msan/Linux/tcgetattr.cc | 21 | ||||
| -rw-r--r-- | test/msan/Linux/xattr.cc | 145 | ||||
| -rw-r--r-- | test/msan/Linux/xattr_test_root/a | 0 |
15 files changed, 554 insertions, 0 deletions
diff --git a/test/msan/Linux/getresid.cc b/test/msan/Linux/getresid.cc new file mode 100644 index 000000000000..385351dfdcde --- /dev/null +++ b/test/msan/Linux/getresid.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 + +#include <assert.h> +#include <unistd.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + uid_t uids[6]; + assert(0 == __msan_test_shadow(uids, 6 * sizeof(uid_t))); + assert(0 == getresuid(&uids[0], &uids[2], &uids[4])); + for (int i = 0; i < 3; i++) + assert(sizeof(uid_t) == + __msan_test_shadow(uids + 2 * i, 2 * sizeof(uid_t))); + + gid_t gids[6]; + assert(0 == __msan_test_shadow(gids, 6 * sizeof(gid_t))); + assert(0 == getresgid(&gids[0], &gids[2], &gids[4])); + for (int i = 0; i < 3; i++) + assert(sizeof(gid_t) == + __msan_test_shadow(gids + 2 * i, 2 * sizeof(gid_t))); + return 0; +} diff --git a/test/msan/Linux/glob.cc b/test/msan/Linux/glob.cc new file mode 100644 index 000000000000..8604e4d76265 --- /dev/null +++ b/test/msan/Linux/glob.cc @@ -0,0 +1,27 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s + +#include <assert.h> +#include <glob.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +int main(int argc, char *argv[]) { + assert(argc == 2); + char buf[1024]; + snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a"); + + glob_t globbuf; + int res = glob(buf, 0, 0, &globbuf); + + printf("%d %s\n", errno, strerror(errno)); + assert(res == 0); + assert(globbuf.gl_pathc == 2); + printf("%zu\n", strlen(globbuf.gl_pathv[0])); + printf("%zu\n", strlen(globbuf.gl_pathv[1])); + printf("PASS\n"); + // CHECK: PASS + return 0; +} diff --git a/test/msan/Linux/glob_altdirfunc.cc b/test/msan/Linux/glob_altdirfunc.cc new file mode 100644 index 000000000000..2c02e735e05e --- /dev/null +++ b/test/msan/Linux/glob_altdirfunc.cc @@ -0,0 +1,78 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s + +#include <assert.h> +#include <glob.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> + +#include <sanitizer/msan_interface.h> + +static void my_gl_closedir(void *dir) { + if (!dir) + exit(1); + closedir((DIR *)dir); +} + +static struct dirent *my_gl_readdir(void *dir) { + if (!dir) + exit(1); + struct dirent *d = readdir((DIR *)dir); + if (d) __msan_poison(d, d->d_reclen); // hehe + return d; +} + +static void *my_gl_opendir(const char *s) { + assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1); + return opendir(s); +} + +static int my_gl_lstat(const char *s, struct stat *st) { + assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1); + if (!st) + exit(1); + return lstat(s, st); +} + +static int my_gl_stat(const char *s, struct stat *st) { + assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1); + if (!st) + exit(1); + return lstat(s, st); +} + +int main(int argc, char *argv[]) { + assert(argc == 2); + char buf[1024]; + snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a"); + + glob_t globbuf; + globbuf.gl_closedir = my_gl_closedir; + globbuf.gl_readdir = my_gl_readdir; + globbuf.gl_opendir = my_gl_opendir; + globbuf.gl_lstat = my_gl_lstat; + globbuf.gl_stat = my_gl_stat; + for (int i = 0; i < 10000; ++i) { + int res = glob(buf, GLOB_ALTDIRFUNC | GLOB_MARK, 0, &globbuf); + assert(res == 0); + printf("%d %s\n", errno, strerror(errno)); + assert(globbuf.gl_pathc == 2); + printf("%zu\n", strlen(globbuf.gl_pathv[0])); + printf("%zu\n", strlen(globbuf.gl_pathv[1])); + __msan_poison(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0]) + 1); + __msan_poison(globbuf.gl_pathv[1], strlen(globbuf.gl_pathv[1]) + 1); + globfree(&globbuf); + } + + printf("PASS\n"); + // CHECK: PASS + return 0; +} diff --git a/test/msan/Linux/glob_nomatch.cc b/test/msan/Linux/glob_nomatch.cc new file mode 100644 index 000000000000..bc35c30d6d07 --- /dev/null +++ b/test/msan/Linux/glob_nomatch.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p + +#include <assert.h> +#include <glob.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { + assert(argc == 2); + char buf[1024]; + snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*c"); + + glob_t globbuf; + int res = glob(buf, 0, 0, &globbuf); + assert(res == GLOB_NOMATCH); + assert(globbuf.gl_pathc == 0); + if (globbuf.gl_pathv == 0) + exit(0); + return 0; +} diff --git a/test/msan/Linux/glob_test_root/aa b/test/msan/Linux/glob_test_root/aa new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/msan/Linux/glob_test_root/aa diff --git a/test/msan/Linux/glob_test_root/ab b/test/msan/Linux/glob_test_root/ab new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/msan/Linux/glob_test_root/ab diff --git a/test/msan/Linux/glob_test_root/ba b/test/msan/Linux/glob_test_root/ba new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/msan/Linux/glob_test_root/ba diff --git a/test/msan/Linux/lit.local.cfg b/test/msan/Linux/lit.local.cfg new file mode 100644 index 000000000000..57271b8078a4 --- /dev/null +++ b/test/msan/Linux/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Linux']: + config.unsupported = True diff --git a/test/msan/Linux/sunrpc.cc b/test/msan/Linux/sunrpc.cc new file mode 100644 index 000000000000..78645a7dcbf2 --- /dev/null +++ b/test/msan/Linux/sunrpc.cc @@ -0,0 +1,40 @@ +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \ +// RUN: %run %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \ +// RUN: %run %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \ +// RUN: %run %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + TYPE x; +#ifndef UNINIT + x = 42; +#endif + bool_t res = FN(&xdrs, &x); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + TYPE y; + res = FN(&xdrs, &y); + assert(res == TRUE); + assert(__msan_test_shadow(&y, sizeof(y)) == -1); + xdr_destroy(&xdrs); + return 0; +} diff --git a/test/msan/Linux/sunrpc_bytes.cc b/test/msan/Linux/sunrpc_bytes.cc new file mode 100644 index 000000000000..f0c35746f34d --- /dev/null +++ b/test/msan/Linux/sunrpc_bytes.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %run %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <string.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + char s[20]; +#ifndef UNINIT + strcpy(s, "hello"); +#endif + char *sp = s; + unsigned sz = 6; + bool_t res = xdr_bytes(&xdrs, &sp, &sz, sizeof(s)); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc_bytes.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + char s2[20]; + char *sp2 = s2; + unsigned sz2; + res = xdr_bytes(&xdrs, &sp2, &sz2, sizeof(s2)); + assert(res == TRUE); + assert(sz == sz2); + assert(strcmp(s, s2) == 0); + xdr_destroy(&xdrs); + return 0; +} diff --git a/test/msan/Linux/sunrpc_string.cc b/test/msan/Linux/sunrpc_string.cc new file mode 100644 index 000000000000..3f44a96d114c --- /dev/null +++ b/test/msan/Linux/sunrpc_string.cc @@ -0,0 +1,35 @@ +// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %run %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <string.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + char s[20]; +#ifndef UNINIT + strcpy(s, "hello"); +#endif + char *sp = s; + bool_t res = xdr_string(&xdrs, &sp, sizeof(s)); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc_string.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + char s2[20]; + char *sp2 = s2; + res = xdr_string(&xdrs, &sp2, sizeof(s2)); + assert(res == TRUE); + assert(strcmp(s, s2) == 0); + xdr_destroy(&xdrs); + return 0; +} diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc new file mode 100644 index 000000000000..4dd97e745148 --- /dev/null +++ b/test/msan/Linux/syscalls.cc @@ -0,0 +1,115 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1 + +#include <assert.h> +#include <errno.h> +#include <glob.h> +#include <stdio.h> +#include <string.h> + +#include <linux/aio_abi.h> +#include <sys/ptrace.h> +#include <sys/stat.h> +#include <sys/uio.h> + +#include <sanitizer/linux_syscall_hooks.h> +#include <sanitizer/msan_interface.h> + +/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general + sanity of their behaviour. */ + +int main(int argc, char *argv[]) { + char buf[1000]; + const int kTen = 10; + const int kFortyTwo = 42; + memset(buf, 0, sizeof(buf)); + __msan_unpoison(buf, sizeof(buf)); + __sanitizer_syscall_pre_recvmsg(0, buf, 0); + __sanitizer_syscall_pre_rt_sigpending(buf, kTen); + __sanitizer_syscall_pre_getdents(0, buf, kTen); + __sanitizer_syscall_pre_getdents64(0, buf, kTen); + + __msan_unpoison(buf, sizeof(buf)); + __sanitizer_syscall_post_recvmsg(0, 0, buf, 0); + __sanitizer_syscall_post_rt_sigpending(-1, buf, kTen); + __sanitizer_syscall_post_getdents(0, 0, buf, kTen); + __sanitizer_syscall_post_getdents64(0, 0, buf, kTen); + assert(__msan_test_shadow(buf, sizeof(buf)) == -1); + + __msan_unpoison(buf, sizeof(buf)); + __sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0); + + // Tell the kernel that the output struct size is 10 bytes, verify that those + // bytes are unpoisoned, and the next byte is not. + __msan_poison(buf, kTen + 1); + __sanitizer_syscall_post_rt_sigpending(0, buf, kTen); + assert(__msan_test_shadow(buf, sizeof(buf)) == kTen); + + __msan_poison(buf, kTen + 1); + __sanitizer_syscall_post_getdents(kTen, 0, buf, kTen); + assert(__msan_test_shadow(buf, sizeof(buf)) == kTen); + + __msan_poison(buf, kTen + 1); + __sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen); + assert(__msan_test_shadow(buf, sizeof(buf)) == kTen); + + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_clock_getres(0, 0, buf); + assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2); + + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_clock_gettime(0, 0, buf); + assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2); + + // Failed syscall does not write to the buffer. + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_clock_gettime(-1, 0, buf); + assert(__msan_test_shadow(buf, sizeof(buf)) == 0); + + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_read(5, 42, buf, 10); + assert(__msan_test_shadow(buf, sizeof(buf)) == 5); + + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_newfstatat(0, 5, "/path/to/file", buf, 0); + assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(struct stat)); + + __msan_poison(buf, sizeof(buf)); + int prio = 0; + __sanitizer_syscall_post_mq_timedreceive(kFortyTwo, 5, buf, sizeof(buf), &prio, 0); + assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo); + assert(__msan_test_shadow(&prio, sizeof(prio)) == -1); + + __msan_poison(buf, sizeof(buf)); + __sanitizer_syscall_post_ptrace(0, PTRACE_PEEKUSER, kFortyTwo, 0xABCD, buf); + assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(void *)); + + __msan_poison(buf, sizeof(buf)); + struct iocb iocb[3]; + struct iocb *iocbp[3] = { &iocb[0], &iocb[1], &iocb[2] }; + memset(iocb, 0, sizeof(iocb)); + iocb[0].aio_lio_opcode = IOCB_CMD_PREAD; + iocb[0].aio_buf = (__u64)buf; + iocb[0].aio_nbytes = 10; + iocb[1].aio_lio_opcode = IOCB_CMD_PREAD; + iocb[1].aio_buf = (__u64)(&buf[20]); + iocb[1].aio_nbytes = 15; + struct iovec vec[2] = { {&buf[40], 3}, {&buf[50], 20} }; + iocb[2].aio_lio_opcode = IOCB_CMD_PREADV; + iocb[2].aio_buf = (__u64)(&vec); + iocb[2].aio_nbytes = 2; + __sanitizer_syscall_pre_io_submit(0, 3, &iocbp); + assert(__msan_test_shadow(buf, sizeof(buf)) == 10); + assert(__msan_test_shadow(buf + 20, sizeof(buf) - 20) == 15); + assert(__msan_test_shadow(buf + 40, sizeof(buf) - 40) == 3); + assert(__msan_test_shadow(buf + 50, sizeof(buf) - 50) == 20); + + __msan_poison(buf, sizeof(buf)); + char *p = buf; + __msan_poison(&p, sizeof(p)); + __sanitizer_syscall_post_io_setup(0, 1, &p); + assert(__msan_test_shadow(&p, sizeof(p)) == -1); + assert(__msan_test_shadow(buf, sizeof(buf)) >= 32); + + return 0; +} diff --git a/test/msan/Linux/tcgetattr.cc b/test/msan/Linux/tcgetattr.cc new file mode 100644 index 000000000000..e1425b84f550 --- /dev/null +++ b/test/msan/Linux/tcgetattr.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p + +#include <assert.h> +#include <glob.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> + +int main(int argc, char *argv[]) { + int fd = getpt(); + assert(fd >= 0); + + struct termios t; + int res = tcgetattr(fd, &t); + assert(!res); + + if (t.c_iflag == 0) + exit(0); + return 0; +} diff --git a/test/msan/Linux/xattr.cc b/test/msan/Linux/xattr.cc new file mode 100644 index 000000000000..1beba117d574 --- /dev/null +++ b/test/msan/Linux/xattr.cc @@ -0,0 +1,145 @@ +// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 + +#include <argz.h> +#include <assert.h> +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sanitizer/msan_interface.h> + +// Do not depend on libattr headers. +#ifndef ENOATTR +#define ENOATTR ENODATA +#endif + +extern "C" { +ssize_t listxattr(const char *path, char *list, size_t size); +ssize_t llistxattr(const char *path, char *list, size_t size); +ssize_t flistxattr(int fd, char *list, size_t size); +ssize_t getxattr(const char *path, const char *name, void *value, size_t size); +ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); +ssize_t fgetxattr(int fd, const char *name, void *value, size_t size); +} + +char g_path[1024]; +int g_fd; + +// Life before closures... +ssize_t listxattr_wrapper(char *buf, size_t size) { + return listxattr(g_path, buf, size); +} + +ssize_t llistxattr_wrapper(char *buf, size_t size) { + return llistxattr(g_path, buf, size); +} + +ssize_t flistxattr_wrapper(char *buf, size_t size) { + return flistxattr(g_fd, buf, size); +} + +ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) { + return getxattr(g_path, name, buf, size); +} + +ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) { + return lgetxattr(g_path, name, buf, size); +} + +ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) { + return fgetxattr(g_fd, name, buf, size); +} + +size_t test_list(ssize_t fun(char*, size_t), char **buf) { + int buf_size = 1024; + while (true) { + *buf = (char *)malloc(buf_size); + assert(__msan_test_shadow(*buf, buf_size) != -1); + ssize_t res = fun(*buf, buf_size); + if (res >= 0) { + assert(__msan_test_shadow(*buf, buf_size) == res); + return res; + } + if (errno == ENOTSUP) { + printf("Extended attributes are disabled. *xattr test is a no-op.\n"); + exit(0); + } + assert(errno == ERANGE); + free(*buf); + buf_size *= 2; + } +} + +// True means success. False means result inconclusive because we don't have +// access to this attribute. +bool test_get_single_attr(ssize_t fun(const char *, char *, size_t), + const char *attr_name) { + char *buf; + int buf_size = 1024; + while (true) { + buf = (char *)malloc(buf_size); + assert(__msan_test_shadow(buf, buf_size) != -1); + ssize_t res = fun(attr_name, buf, buf_size); + if (res >= 0) { + assert(__msan_test_shadow(buf, buf_size) == res); + free(buf); + return true; + } + if (errno == ENOTSUP) { + printf("Extended attributes are disabled. *xattr test is a no-op.\n"); + exit(0); + } + if (errno == ENOATTR) + return false; + assert(errno == ERANGE); + free(buf); + buf_size *= 2; + } +} + +void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list, + size_t attr_list_size) { + // Try every attribute, until we see one we can access. Attribute names are + // null-separated strings in attr_list. + size_t attr_list_len = argz_count(attr_list, attr_list_size); + size_t argv_size = (attr_list_len + 1) * sizeof(char *); + char **attrs = (char **)malloc(argv_size); + argz_extract(attr_list, attr_list_size, attrs); + // TODO(smatveev): we need proper argz_* interceptors + __msan_unpoison(attrs, argv_size); + for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) { + if (test_get_single_attr(fun, attrs[i])) + return; + } + printf("*xattr test could not access any attributes.\n"); +} + +// TODO: set some attributes before trying to retrieve them with *getxattr. +// Currently the list is empty, so *getxattr is not tested. +int main(int argc, char *argv[]) { + assert(argc == 2); + snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a"); + + g_fd = open(g_path, O_RDONLY); + assert(g_fd); + + char *attr_list; + size_t attr_list_size; + attr_list_size = test_list(listxattr_wrapper, &attr_list); + free(attr_list); + attr_list_size = test_list(llistxattr_wrapper, &attr_list); + free(attr_list); + attr_list_size = test_list(flistxattr_wrapper, &attr_list); + + test_get(getxattr_wrapper, attr_list, attr_list_size); + test_get(lgetxattr_wrapper, attr_list, attr_list_size); + test_get(fgetxattr_wrapper, attr_list, attr_list_size); + + free(attr_list); + return 0; +} diff --git a/test/msan/Linux/xattr_test_root/a b/test/msan/Linux/xattr_test_root/a new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/msan/Linux/xattr_test_root/a |
