[AA] Rename CaptureInfo -> CaptureAnalysis (NFC) (#116842)
[llvm-project.git] / compiler-rt / test / msan / vararg_shadow.cpp
blob20e55da5bce3177aae262bc5fefb483550288021
1 // Check that shadow of retrieved value from va_list matches the shadow of passed value.
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
6 // FIXME: The rest is likely still broken.
7 // XFAIL: target={{(loongarch64|mips|powerpc64).*}}
9 #include <sanitizer/msan_interface.h>
10 #include <stdarg.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
15 #ifdef DEBUG_VARARG_SHADOW_TEST
16 __attribute__((noinline, no_sanitize("memory"))) void
17 printb(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");
27 struct 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
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);
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);
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
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]);
80 fprintf(stderr, "\n");
82 #endif // DEBUG_VARARG_SHADOW_TEST
84 const int kMsanParamTlsSize = 800;
85 extern "C" __thread uint8_t __msan_va_arg_tls[];
87 struct IntInt {
88 int a;
89 int b;
92 struct Int64Int64 {
93 int64_t a;
94 int64_t b;
97 struct DoubleDouble {
98 double a;
99 double b;
102 struct Double4 {
103 double a[4];
106 struct DoubleFloat {
107 double a;
108 float b;
111 struct LongDouble2 {
112 long double a[2];
115 struct LongDouble4 {
116 long double a[4];
119 template <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, "\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, "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
136 template <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);
149 template <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);
162 template <class T> __attribute__((noinline)) void test() {
163 // Array of values we will pass into variadic functions.
164 static T args[32] = {};
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);
174 #ifdef DEBUG_VARARG_SHADOW_TEST
175 __msan_print_shadow(args, sizeof(args));
176 #endif
178 // Now we will check that index, printed like 'i:03' will match
179 // '0x123abc[0x123abc] 03 ff ff ff'
180 memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
181 test1<T>(1, args[1]);
182 // CHECK-COUNT-1: ArgShadow fn:test1 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
184 memset(__msan_va_arg_tls, 0xee, 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]]
188 memset(__msan_va_arg_tls, 0xee, 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]]
194 memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
195 test2<T>(args[31], 1, args[1]);
196 // CHECK-COUNT-1: ArgShadow fn:test2 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
198 memset(__msan_va_arg_tls, 0xee, 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]]
202 memset(__msan_va_arg_tls, 0xee, 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]]
210 int main(int argc, char *argv[]) {
211 #define TEST(T...) \
212 if (argc == 2 && strcmp(argv[1], #T) == 0) { \
213 test<T>(); \
214 return 0; \
217 TEST(char);
218 // RUN: %run %t char 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
220 TEST(int);
221 // RUN: %run %t int 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
223 TEST(void*);
224 // RUN: %run %t "void*" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
226 TEST(float);
227 // RUN: %run %t float 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
229 TEST(double);
230 // RUN: %run %t double 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
232 TEST(long double);
233 // RUN: %run %t "long double" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
235 TEST(IntInt);
236 // RUN: %run %t IntInt 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
238 TEST(Int64Int64);
239 // RUN: %run %t Int64Int64 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
241 TEST(DoubleDouble);
242 // RUN: %run %t DoubleDouble 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
244 TEST(Double4);
245 // RUN: %run %t Double4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
247 TEST(DoubleFloat);
248 // RUN: %run %t DoubleFloat 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
250 TEST(LongDouble2);
251 // RUN: %run %t LongDouble2 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
253 TEST(LongDouble4);
254 // RUN: %run %t LongDouble4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
256 return 1;