1// Check that shadow of retrieved value from va_list matches the shadow of passed value.
2
3// Without -fno-sanitize-memory-param-retval we can't even pass poisoned values.
4// RUN: %clangxx_msan -fno-sanitize-memory-param-retval -fsanitize-memory-track-origins=0 -O3 %s -o %t
5
6// FIXME: The rest is likely still broken.
7// XFAIL: target={{(loongarch64|mips|powerpc64).*}}
8
9#include <sanitizer/msan_interface.h>
10#include <stdarg.h>
11#include <stdint.h>
12#include <stdio.h>
13#include <string.h>
14
15#ifdef DEBUG_VARARG_SHADOW_TEST
16__attribute__((noinline, no_sanitize("memory"))) void
17printb(const void *p, size_t n, int line, int align) {
18 fprintf(stderr, "\n%p at line %d: \n", p, line);
19 for (int i = 0; i < n;) {
20 fprintf(stderr, "%p: ", (void *)(((uint8_t *)p) + i));
21 for (int j = 0; j < align; ++i, ++j)
22 fprintf(stderr, "%02x ", ((uint8_t *)p)[i]);
23 fprintf(stderr, "\n");
24 }
25}
26
27struct my_va_list {
28# ifdef __ARM_ARCH_ISA_A64
29 void *stack;
30 void *gr_top;
31 void *vr_top;
32 int gr_offs;
33 int vr_offs;
34# else
35 unsigned int gp_offset;
36 unsigned int fp_offset;
37 void *overflow_arg_area;
38 void *reg_save_area;
39# endif
40};
41
42__attribute__((noinline, no_sanitize("memory"))) void printva(const void *p,
43 int line) {
44 my_va_list *pp = (my_va_list *)p;
45# ifdef __ARM_ARCH_ISA_A64
46 fprintf(stderr,
47 "\nva %p at line %d: stack : %p\n gr_top: %p\n vr_top: %p\n gr_offs: "
48 "%d\n "
49 "vr_offs: %d\n",
50 p, line, pp->stack, pp->gr_top, pp->vr_top, pp->gr_offs, pp->vr_offs);
51
52 printb((char *)pp->gr_top + pp->gr_offs, -pp->gr_offs, __LINE__, 8);
53 printb((char *)pp->vr_top + pp->vr_offs, -pp->vr_offs, __LINE__, 16);
54 printb((char *)pp->stack, 256, __LINE__, 8);
55# else
56 fprintf(stderr,
57 "\nva %p at line %d:\n gp_offset: %u\n fp_offset: %u\n "
58 "overflow_arg_area: %p\n reg_save_area: %p\n\n",
59 p, line, pp->gp_offset, pp->fp_offset, pp->overflow_arg_area,
60 pp->reg_save_area);
61
62 printb((char *)pp->reg_save_area + pp->gp_offset,
63 pp->fp_offset - pp->gp_offset, __LINE__, 8);
64 printb((char *)pp->reg_save_area + pp->fp_offset, 128, __LINE__, 16);
65 printb((char *)pp->overflow_arg_area, 256, __LINE__, 8);
66# endif
67}
68
69__attribute__((noinline, no_sanitize("memory"))) void printtls(int line) {
70 uint8_t tmp[kMsanParamTlsSize];
71 for (int i = 0; i < kMsanParamTlsSize; ++i)
72 tmp[i] = __msan_va_arg_tls[i];
73 fprintf(stderr, "\nTLS at line %d: ", line);
74 for (int i = 0; i < kMsanParamTlsSize;) {
75 fprintf(stderr, "\n");
76 for (int j = 0; j < 16; ++i, ++j)
77 fprintf(stderr, "%02x ", tmp[i]);
78 }
79
80 fprintf(stderr, "\n");
81}
82#endif // DEBUG_VARARG_SHADOW_TEST
83
84const int kMsanParamTlsSize = 800;
85extern "C" __thread uint8_t __msan_va_arg_tls[];
86
87struct IntInt {
88 int a;
89 int b;
90};
91
92struct Int64Int64 {
93 int64_t a;
94 int64_t b;
95};
96
97struct DoubleDouble {
98 double a;
99 double b;
100};
101
102struct Double4 {
103 double a[4];
104};
105
106struct DoubleFloat {
107 double a;
108 float b;
109};
110
111struct LongDouble2 {
112 long double a[2];
113};
114
115struct LongDouble4 {
116 long double a[4];
117};
118
119template <class T>
120__attribute__((noinline)) void print_shadow(va_list &args, int n,
121 const char *function) {
122 for (int i = 0; i < n; i++) {
123 // 1-based to make it different from clean shadow.
124 fprintf(stderr, format: "\nArgShadow fn:%s n:%d i:%02x ", function, n, i + 1);
125 T arg_int = va_arg(args, T);
126 if (__msan_test_shadow(&arg_int, sizeof(arg_int)))
127 fprintf(stderr, format: "fake[clean] %02x", i + 1);
128 else
129 __msan_dump_shadow(&arg_int, sizeof(arg_int));
130#ifdef DEBUG_VARARG_SHADOW_TEST
131 printb(&arg_int, sizeof(arg_int), __LINE__, 16);
132#endif
133 }
134}
135
136template <class T> __attribute__((noinline)) void test1(int n, ...) {
137#ifdef DEBUG_VARARG_SHADOW_TEST
138 printtls(__LINE__);
139#endif
140 va_list args;
141 va_start(args, n);
142#ifdef DEBUG_VARARG_SHADOW_TEST
143 printva(&args, __LINE__);
144#endif
145 print_shadow<T>(args, n, __FUNCTION__);
146 va_end(args);
147}
148
149template <class T> __attribute__((noinline)) void test2(T t, int n, ...) {
150#ifdef DEBUG_VARARG_SHADOW_TEST
151 printtls(__LINE__);
152#endif
153 va_list args;
154 va_start(args, n);
155#ifdef DEBUG_VARARG_SHADOW_TEST
156 printva(&args, __LINE__);
157#endif
158 print_shadow<T>(args, n, __FUNCTION__);
159 va_end(args);
160}
161
162template <class T> __attribute__((noinline)) void test() {
163 // Array of values we will pass into variadic functions.
164 static T args[32] = {};
165
166 // Poison values making the fist byte of the item shadow match the index.
167 // E.g. item 3 should be poisoned as '03 ff ff ff'.
168 memset(args, 0xff, sizeof(args));
169 __msan_poison(args, sizeof(args));
170 for (int i = 0; i < 32; ++i) {
171 char *first = (char *)(&args[i]);
172 *first = char(*(int *)(first)&i);
173 }
174#ifdef DEBUG_VARARG_SHADOW_TEST
175 __msan_print_shadow(args, sizeof(args));
176#endif
177
178 // Now we will check that index, printed like 'i:03' will match
179 // '0x123abc[0x123abc] 03 ff ff ff'
180 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
181 test1<T>(1, args[1]);
182 // CHECK-COUNT-1: ArgShadow fn:test1 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
183
184 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
185 test1<T>(4, args[1], args[2], args[3], args[4]);
186 // CHECK-COUNT-4: ArgShadow fn:test1 n:4 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
187
188 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
189 test1<T>(20, args[1], args[2], args[3], args[4], args[5], args[6], args[7],
190 args[8], args[9], args[10], args[11], args[12], args[13], args[14],
191 args[15], args[16], args[17], args[18], args[19], args[20]);
192 // CHECK-COUNT-20: ArgShadow fn:test1 n:20 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
193
194 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
195 test2<T>(args[31], 1, args[1]);
196 // CHECK-COUNT-1: ArgShadow fn:test2 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
197
198 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
199 test2<T>(args[31], 4, args[1], args[2], args[3], args[4]);
200 // CHECK-COUNT-4: ArgShadow fn:test2 n:4 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
201
202 memset(s: __msan_va_arg_tls, c: 0xee, n: kMsanParamTlsSize);
203 test2<T>(args[31], 20, args[1], args[2], args[3], args[4], args[5], args[6],
204 args[7], args[8], args[9], args[10], args[11], args[12], args[13],
205 args[14], args[15], args[16], args[17], args[18], args[19],
206 args[20]);
207 // CHECK-COUNT-20: ArgShadow fn:test2 n:20 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
208}
209
210int main(int argc, char *argv[]) {
211#define TEST(T...) \
212 if (argc == 2 && strcmp(argv[1], #T) == 0) { \
213 test<T>(); \
214 return 0; \
215 }
216
217 TEST(char);
218 // RUN: %run %t char 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
219
220 TEST(int);
221 // RUN: %run %t int 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
222
223 TEST(void*);
224 // RUN: %run %t "void*" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
225
226 TEST(float);
227 // RUN: %run %t float 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
228
229 TEST(double);
230 // RUN: %run %t double 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
231
232 TEST(long double);
233 // RUN: %run %t "long double" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
234
235 TEST(IntInt);
236 // RUN: %run %t IntInt 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
237
238 TEST(Int64Int64);
239 // RUN: %run %t Int64Int64 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
240
241 TEST(DoubleDouble);
242 // RUN: %run %t DoubleDouble 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
243
244 TEST(Double4);
245 // RUN: %run %t Double4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
246
247 TEST(DoubleFloat);
248 // RUN: %run %t DoubleFloat 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
249
250 TEST(LongDouble2);
251 // RUN: %run %t LongDouble2 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
252
253 TEST(LongDouble4);
254 // RUN: %run %t LongDouble4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
255
256 return 1;
257}
258

source code of compiler-rt/test/msan/vararg_shadow.cpp