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>
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");
28 # ifdef __ARM_ARCH_ISA_A64
35 unsigned int gp_offset
;
36 unsigned int fp_offset
;
37 void *overflow_arg_area
;
42 __attribute__((noinline
, no_sanitize("memory"))) void printva(const void *p
,
44 my_va_list
*pp
= (my_va_list
*)p
;
45 # ifdef __ARM_ARCH_ISA_A64
47 "\nva %p at line %d: stack : %p\n gr_top: %p\n vr_top: %p\n gr_offs: "
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);
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
,
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);
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
[];
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);
129 __msan_dump_shadow(&arg_int
, sizeof(arg_int
));
130 #ifdef DEBUG_VARARG_SHADOW_TEST
131 printb(&arg_int
, sizeof(arg_int
), __LINE__
, 16);
136 template <class T
> __attribute__((noinline
)) void test1(int n
, ...) {
137 #ifdef DEBUG_VARARG_SHADOW_TEST
142 #ifdef DEBUG_VARARG_SHADOW_TEST
143 printva(&args
, __LINE__
);
145 print_shadow
<T
>(args
, n
, __FUNCTION__
);
149 template <class T
> __attribute__((noinline
)) void test2(T t
, int n
, ...) {
150 #ifdef DEBUG_VARARG_SHADOW_TEST
155 #ifdef DEBUG_VARARG_SHADOW_TEST
156 printva(&args
, __LINE__
);
158 print_shadow
<T
>(args
, n
, __FUNCTION__
);
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
));
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],
207 // CHECK-COUNT-20: ArgShadow fn:test2 n:20 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
210 int main(int argc
, char *argv
[]) {
212 if (argc == 2 && strcmp(argv[1], #T) == 0) { \
218 // RUN: %run %t char 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
221 // RUN: %run %t int 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
224 // RUN: %run %t "void*" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
227 // RUN: %run %t float 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
230 // RUN: %run %t double 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
233 // RUN: %run %t "long double" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
236 // RUN: %run %t IntInt 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
239 // RUN: %run %t Int64Int64 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
242 // RUN: %run %t DoubleDouble 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
245 // RUN: %run %t Double4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
248 // RUN: %run %t DoubleFloat 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
251 // RUN: %run %t LongDouble2 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
254 // RUN: %run %t LongDouble4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"