Skip to content

Commit 37db332

Browse files
authored
[test][msan] Precommit tests for vararg improvements (#72612)
1 parent ae182db commit 37db332

File tree

3 files changed

+3458
-0
lines changed

3 files changed

+3458
-0
lines changed
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
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+
// Nothing works yet.
7+
// XFAIL: *
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
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");
24+
}
25+
}
26+
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
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+
84+
const int kMsanParamTlsSize = 800;
85+
extern "C" __thread uint8_t __msan_va_arg_tls[];
86+
87+
struct IntInt {
88+
int a;
89+
int b;
90+
};
91+
92+
struct Int64Int64 {
93+
int64_t a;
94+
int64_t b;
95+
};
96+
97+
struct DoubleDouble {
98+
double a;
99+
double b;
100+
};
101+
102+
struct Double4 {
103+
double a[4];
104+
};
105+
106+
struct DoubleFloat {
107+
double a;
108+
float b;
109+
};
110+
111+
struct LongDouble2 {
112+
long double a[2];
113+
};
114+
115+
struct LongDouble4 {
116+
long double a[4];
117+
};
118+
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
133+
}
134+
}
135+
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);
147+
}
148+
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);
160+
}
161+
162+
template <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(__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]]
183+
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]]
187+
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]]
193+
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]]
197+
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]]
201+
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]]
208+
}
209+
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; \
215+
}
216+
217+
TEST(char);
218+
// RUN: %run %t char 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
219+
220+
TEST(int);
221+
// RUN: %run %t int 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
222+
223+
TEST(float);
224+
// RUN: %run %t float 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
225+
226+
TEST(double);
227+
// RUN: %run %t double 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
228+
229+
TEST(long double);
230+
// RUN: %run %t "long double" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
231+
232+
TEST(IntInt);
233+
// RUN: %run %t IntInt 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
234+
235+
TEST(Int64Int64);
236+
// RUN: %run %t Int64Int64 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
237+
238+
TEST(DoubleDouble);
239+
// RUN: %run %t DoubleDouble 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
240+
241+
TEST(Double4);
242+
// RUN: %run %t Double4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
243+
244+
TEST(DoubleFloat);
245+
// RUN: %run %t DoubleFloat 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
246+
247+
TEST(LongDouble2);
248+
// RUN: %run %t LongDouble2 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
249+
250+
TEST(LongDouble4);
251+
// RUN: %run %t LongDouble4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow" --check-prefixes=CHECK
252+
253+
return 1;
254+
}

0 commit comments

Comments
 (0)