aboutsummaryrefslogtreecommitdiff
path: root/test/msan/Linux/xattr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/msan/Linux/xattr.cc')
-rw-r--r--test/msan/Linux/xattr.cc145
1 files changed, 145 insertions, 0 deletions
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;
+}