1// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1
2// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
3// RUN: %clangxx_msan -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
21extern "C" {
22ssize_t listxattr(const char *path, char *list, size_t size);
23ssize_t llistxattr(const char *path, char *list, size_t size);
24ssize_t flistxattr(int fd, char *list, size_t size);
25ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
26ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
27ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
28}
29
30char g_path[1024];
31int g_fd;
32
33// Life before closures...
34ssize_t listxattr_wrapper(char *buf, size_t size) {
35 return listxattr(path: g_path, list: buf, size);
36}
37
38ssize_t llistxattr_wrapper(char *buf, size_t size) {
39 return llistxattr(path: g_path, list: buf, size);
40}
41
42ssize_t flistxattr_wrapper(char *buf, size_t size) {
43 return flistxattr(fd: g_fd, list: buf, size);
44}
45
46ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
47 return getxattr(path: g_path, name, value: buf, size);
48}
49
50ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
51 return lgetxattr(path: g_path, name, value: buf, size);
52}
53
54ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
55 return fgetxattr(fd: g_fd, name, value: buf, size);
56}
57
58size_t test_list(ssize_t fun(char*, size_t), char **buf) {
59 int buf_size = 1024;
60 while (true) {
61 *buf = (char *)malloc(size: 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(format: "Extended attributes are disabled. *xattr test is a no-op.\n");
70 exit(status: 0);
71 }
72 assert(errno == ERANGE);
73 free(ptr: *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.
80bool 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(size: 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(ptr: buf);
91 return true;
92 }
93 if (errno == ENOTSUP) {
94 printf(format: "Extended attributes are disabled. *xattr test is a no-op.\n");
95 exit(status: 0);
96 }
97 if (errno == ENOATTR)
98 return false;
99 assert(errno == ERANGE);
100 free(ptr: buf);
101 buf_size *= 2;
102 }
103}
104
105void 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(argz: attr_list, len: attr_list_size);
110 size_t argv_size = (attr_list_len + 1) * sizeof(char *);
111 char **attrs = (char **)malloc(size: argv_size);
112 argz_extract(argz: attr_list, len: attr_list_size, argv: attrs);
113 // TODO(smatveev): we need proper argz_* interceptors
114 __msan_unpoison(a: attrs, size: argv_size);
115 for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) {
116 if (test_get_single_attr(fun, attr_name: attrs[i]))
117 return;
118 }
119 printf(format: "*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.
124int main(int argc, char *argv[]) {
125 assert(argc == 2);
126 snprintf(s: g_path, maxlen: sizeof(g_path), format: "%s/%s", argv[1], "xattr_test_root/a");
127
128 g_fd = open(file: 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(fun: listxattr_wrapper, buf: &attr_list);
134 free(ptr: attr_list);
135 attr_list_size = test_list(fun: llistxattr_wrapper, buf: &attr_list);
136 free(ptr: attr_list);
137 attr_list_size = test_list(fun: flistxattr_wrapper, buf: &attr_list);
138
139 test_get(fun: getxattr_wrapper, attr_list, attr_list_size);
140 test_get(fun: lgetxattr_wrapper, attr_list, attr_list_size);
141 test_get(fun: fgetxattr_wrapper, attr_list, attr_list_size);
142
143 free(ptr: attr_list);
144 return 0;
145}
146

source code of compiler-rt/test/msan/Linux/xattr.cpp