1 // RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 2 // RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 3 // RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 4 5 #include <argz.h> 6 #include <assert.h> 7 #include <sys/types.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <sanitizer/msan_interface.h> 15 16 // Do not depend on libattr headers. 17 #ifndef ENOATTR 18 #define ENOATTR ENODATA 19 #endif 20 21 extern "C" { 22 ssize_t listxattr(const char *path, char *list, size_t size); 23 ssize_t llistxattr(const char *path, char *list, size_t size); 24 ssize_t flistxattr(int fd, char *list, size_t size); 25 ssize_t getxattr(const char *path, const char *name, void *value, size_t size); 26 ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); 27 ssize_t fgetxattr(int fd, const char *name, void *value, size_t size); 28 } 29 30 char g_path[1024]; 31 int g_fd; 32 33 // Life before closures... 34 ssize_t listxattr_wrapper(char *buf, size_t size) { 35 return listxattr(g_path, buf, size); 36 } 37 38 ssize_t llistxattr_wrapper(char *buf, size_t size) { 39 return llistxattr(g_path, buf, size); 40 } 41 42 ssize_t flistxattr_wrapper(char *buf, size_t size) { 43 return flistxattr(g_fd, buf, size); 44 } 45 46 ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) { 47 return getxattr(g_path, name, buf, size); 48 } 49 50 ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) { 51 return lgetxattr(g_path, name, buf, size); 52 } 53 54 ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) { 55 return fgetxattr(g_fd, name, buf, size); 56 } 57 58 size_t test_list(ssize_t fun(char*, size_t), char **buf) { 59 int buf_size = 1024; 60 while (true) { 61 *buf = (char *)malloc(buf_size); 62 assert(__msan_test_shadow(*buf, buf_size) != -1); 63 ssize_t res = fun(*buf, buf_size); 64 if (res >= 0) { 65 assert(__msan_test_shadow(*buf, buf_size) == res); 66 return res; 67 } 68 if (errno == ENOTSUP) { 69 printf("Extended attributes are disabled. *xattr test is a no-op.\n"); 70 exit(0); 71 } 72 assert(errno == ERANGE); 73 free(*buf); 74 buf_size *= 2; 75 } 76 } 77 78 // True means success. False means result inconclusive because we don't have 79 // access to this attribute. 80 bool test_get_single_attr(ssize_t fun(const char *, char *, size_t), 81 const char *attr_name) { 82 char *buf; 83 int buf_size = 1024; 84 while (true) { 85 buf = (char *)malloc(buf_size); 86 assert(__msan_test_shadow(buf, buf_size) != -1); 87 ssize_t res = fun(attr_name, buf, buf_size); 88 if (res >= 0) { 89 assert(__msan_test_shadow(buf, buf_size) == res); 90 free(buf); 91 return true; 92 } 93 if (errno == ENOTSUP) { 94 printf("Extended attributes are disabled. *xattr test is a no-op.\n"); 95 exit(0); 96 } 97 if (errno == ENOATTR) 98 return false; 99 assert(errno == ERANGE); 100 free(buf); 101 buf_size *= 2; 102 } 103 } 104 105 void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list, 106 size_t attr_list_size) { 107 // Try every attribute, until we see one we can access. Attribute names are 108 // null-separated strings in attr_list. 109 size_t attr_list_len = argz_count(attr_list, attr_list_size); 110 size_t argv_size = (attr_list_len + 1) * sizeof(char *); 111 char **attrs = (char **)malloc(argv_size); 112 argz_extract(attr_list, attr_list_size, attrs); 113 // TODO(smatveev): we need proper argz_* interceptors 114 __msan_unpoison(attrs, argv_size); 115 for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) { 116 if (test_get_single_attr(fun, attrs[i])) 117 return; 118 } 119 printf("*xattr test could not access any attributes.\n"); 120 } 121 122 // TODO: set some attributes before trying to retrieve them with *getxattr. 123 // Currently the list is empty, so *getxattr is not tested. 124 int main(int argc, char *argv[]) { 125 assert(argc == 2); 126 snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a"); 127 128 g_fd = open(g_path, O_RDONLY); 129 assert(g_fd); 130 131 char *attr_list; 132 size_t attr_list_size; 133 attr_list_size = test_list(listxattr_wrapper, &attr_list); 134 free(attr_list); 135 attr_list_size = test_list(llistxattr_wrapper, &attr_list); 136 free(attr_list); 137 attr_list_size = test_list(flistxattr_wrapper, &attr_list); 138 139 test_get(getxattr_wrapper, attr_list, attr_list_size); 140 test_get(lgetxattr_wrapper, attr_list, attr_list_size); 141 test_get(fgetxattr_wrapper, attr_list, attr_list_size); 142 143 free(attr_list); 144 return 0; 145 } 146