137db332cSVitaly Buka // Check that shadow of retrieved value from va_list matches the shadow of passed value.
237db332cSVitaly Buka
337db332cSVitaly Buka // Without -fno-sanitize-memory-param-retval we can't even pass poisoned values.
437db332cSVitaly Buka // RUN: %clangxx_msan -fno-sanitize-memory-param-retval -fsanitize-memory-track-origins=0 -O3 %s -o %t
537db332cSVitaly Buka
666e9429eSVitaly Buka // FIXME: The rest is likely still broken.
766e9429eSVitaly Buka // XFAIL: target={{(loongarch64|mips|powerpc64).*}}
837db332cSVitaly Buka
937db332cSVitaly Buka #include <sanitizer/msan_interface.h>
1037db332cSVitaly Buka #include <stdarg.h>
1137db332cSVitaly Buka #include <stdint.h>
1237db332cSVitaly Buka #include <stdio.h>
1337db332cSVitaly Buka #include <string.h>
1437db332cSVitaly Buka
1537db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
1637db332cSVitaly Buka __attribute__((noinline, no_sanitize("memory"))) void
printb(const void * p,size_t n,int line,int align)1737db332cSVitaly Buka printb(const void *p, size_t n, int line, int align) {
1837db332cSVitaly Buka fprintf(stderr, "\n%p at line %d: \n", p, line);
1937db332cSVitaly Buka for (int i = 0; i < n;) {
2037db332cSVitaly Buka fprintf(stderr, "%p: ", (void *)(((uint8_t *)p) + i));
2137db332cSVitaly Buka for (int j = 0; j < align; ++i, ++j)
2237db332cSVitaly Buka fprintf(stderr, "%02x ", ((uint8_t *)p)[i]);
2337db332cSVitaly Buka fprintf(stderr, "\n");
2437db332cSVitaly Buka }
2537db332cSVitaly Buka }
2637db332cSVitaly Buka
2737db332cSVitaly Buka struct my_va_list {
2837db332cSVitaly Buka # ifdef __ARM_ARCH_ISA_A64
2937db332cSVitaly Buka void *stack;
3037db332cSVitaly Buka void *gr_top;
3137db332cSVitaly Buka void *vr_top;
3237db332cSVitaly Buka int gr_offs;
3337db332cSVitaly Buka int vr_offs;
3437db332cSVitaly Buka # else
3537db332cSVitaly Buka unsigned int gp_offset;
3637db332cSVitaly Buka unsigned int fp_offset;
3737db332cSVitaly Buka void *overflow_arg_area;
3837db332cSVitaly Buka void *reg_save_area;
3937db332cSVitaly Buka # endif
4037db332cSVitaly Buka };
4137db332cSVitaly Buka
printva(const void * p,int line)4237db332cSVitaly Buka __attribute__((noinline, no_sanitize("memory"))) void printva(const void *p,
4337db332cSVitaly Buka int line) {
4437db332cSVitaly Buka my_va_list *pp = (my_va_list *)p;
4537db332cSVitaly Buka # ifdef __ARM_ARCH_ISA_A64
4637db332cSVitaly Buka fprintf(stderr,
4737db332cSVitaly Buka "\nva %p at line %d: stack : %p\n gr_top: %p\n vr_top: %p\n gr_offs: "
4837db332cSVitaly Buka "%d\n "
4937db332cSVitaly Buka "vr_offs: %d\n",
5037db332cSVitaly Buka p, line, pp->stack, pp->gr_top, pp->vr_top, pp->gr_offs, pp->vr_offs);
5137db332cSVitaly Buka
5237db332cSVitaly Buka printb((char *)pp->gr_top + pp->gr_offs, -pp->gr_offs, __LINE__, 8);
5337db332cSVitaly Buka printb((char *)pp->vr_top + pp->vr_offs, -pp->vr_offs, __LINE__, 16);
5437db332cSVitaly Buka printb((char *)pp->stack, 256, __LINE__, 8);
5537db332cSVitaly Buka # else
5637db332cSVitaly Buka fprintf(stderr,
5737db332cSVitaly Buka "\nva %p at line %d:\n gp_offset: %u\n fp_offset: %u\n "
5837db332cSVitaly Buka "overflow_arg_area: %p\n reg_save_area: %p\n\n",
5937db332cSVitaly Buka p, line, pp->gp_offset, pp->fp_offset, pp->overflow_arg_area,
6037db332cSVitaly Buka pp->reg_save_area);
6137db332cSVitaly Buka
6237db332cSVitaly Buka printb((char *)pp->reg_save_area + pp->gp_offset,
6337db332cSVitaly Buka pp->fp_offset - pp->gp_offset, __LINE__, 8);
6437db332cSVitaly Buka printb((char *)pp->reg_save_area + pp->fp_offset, 128, __LINE__, 16);
6537db332cSVitaly Buka printb((char *)pp->overflow_arg_area, 256, __LINE__, 8);
6637db332cSVitaly Buka # endif
6737db332cSVitaly Buka }
6837db332cSVitaly Buka
printtls(int line)6937db332cSVitaly Buka __attribute__((noinline, no_sanitize("memory"))) void printtls(int line) {
7037db332cSVitaly Buka uint8_t tmp[kMsanParamTlsSize];
7137db332cSVitaly Buka for (int i = 0; i < kMsanParamTlsSize; ++i)
7237db332cSVitaly Buka tmp[i] = __msan_va_arg_tls[i];
7337db332cSVitaly Buka fprintf(stderr, "\nTLS at line %d: ", line);
7437db332cSVitaly Buka for (int i = 0; i < kMsanParamTlsSize;) {
7537db332cSVitaly Buka fprintf(stderr, "\n");
7637db332cSVitaly Buka for (int j = 0; j < 16; ++i, ++j)
7737db332cSVitaly Buka fprintf(stderr, "%02x ", tmp[i]);
7837db332cSVitaly Buka }
7937db332cSVitaly Buka
8037db332cSVitaly Buka fprintf(stderr, "\n");
8137db332cSVitaly Buka }
8237db332cSVitaly Buka #endif // DEBUG_VARARG_SHADOW_TEST
8337db332cSVitaly Buka
8437db332cSVitaly Buka const int kMsanParamTlsSize = 800;
8537db332cSVitaly Buka extern "C" __thread uint8_t __msan_va_arg_tls[];
8637db332cSVitaly Buka
8737db332cSVitaly Buka struct IntInt {
8837db332cSVitaly Buka int a;
8937db332cSVitaly Buka int b;
9037db332cSVitaly Buka };
9137db332cSVitaly Buka
9237db332cSVitaly Buka struct Int64Int64 {
9337db332cSVitaly Buka int64_t a;
9437db332cSVitaly Buka int64_t b;
9537db332cSVitaly Buka };
9637db332cSVitaly Buka
9737db332cSVitaly Buka struct DoubleDouble {
9837db332cSVitaly Buka double a;
9937db332cSVitaly Buka double b;
10037db332cSVitaly Buka };
10137db332cSVitaly Buka
10237db332cSVitaly Buka struct Double4 {
10337db332cSVitaly Buka double a[4];
10437db332cSVitaly Buka };
10537db332cSVitaly Buka
10637db332cSVitaly Buka struct DoubleFloat {
10737db332cSVitaly Buka double a;
10837db332cSVitaly Buka float b;
10937db332cSVitaly Buka };
11037db332cSVitaly Buka
11137db332cSVitaly Buka struct LongDouble2 {
11237db332cSVitaly Buka long double a[2];
11337db332cSVitaly Buka };
11437db332cSVitaly Buka
11537db332cSVitaly Buka struct LongDouble4 {
11637db332cSVitaly Buka long double a[4];
11737db332cSVitaly Buka };
11837db332cSVitaly Buka
11937db332cSVitaly Buka template <class T>
print_shadow(va_list & args,int n,const char * function)12037db332cSVitaly Buka __attribute__((noinline)) void print_shadow(va_list &args, int n,
12137db332cSVitaly Buka const char *function) {
12237db332cSVitaly Buka for (int i = 0; i < n; i++) {
12337db332cSVitaly Buka // 1-based to make it different from clean shadow.
12437db332cSVitaly Buka fprintf(stderr, "\nArgShadow fn:%s n:%d i:%02x ", function, n, i + 1);
12537db332cSVitaly Buka T arg_int = va_arg(args, T);
12637db332cSVitaly Buka if (__msan_test_shadow(&arg_int, sizeof(arg_int)))
12737db332cSVitaly Buka fprintf(stderr, "fake[clean] %02x", i + 1);
12837db332cSVitaly Buka else
12937db332cSVitaly Buka __msan_dump_shadow(&arg_int, sizeof(arg_int));
13037db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
13137db332cSVitaly Buka printb(&arg_int, sizeof(arg_int), __LINE__, 16);
13237db332cSVitaly Buka #endif
13337db332cSVitaly Buka }
13437db332cSVitaly Buka }
13537db332cSVitaly Buka
test1(int n,...)13637db332cSVitaly Buka template <class T> __attribute__((noinline)) void test1(int n, ...) {
13737db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
13837db332cSVitaly Buka printtls(__LINE__);
13937db332cSVitaly Buka #endif
14037db332cSVitaly Buka va_list args;
14137db332cSVitaly Buka va_start(args, n);
14237db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
14337db332cSVitaly Buka printva(&args, __LINE__);
14437db332cSVitaly Buka #endif
14537db332cSVitaly Buka print_shadow<T>(args, n, __FUNCTION__);
14637db332cSVitaly Buka va_end(args);
14737db332cSVitaly Buka }
14837db332cSVitaly Buka
test2(T t,int n,...)14937db332cSVitaly Buka template <class T> __attribute__((noinline)) void test2(T t, int n, ...) {
15037db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
15137db332cSVitaly Buka printtls(__LINE__);
15237db332cSVitaly Buka #endif
15337db332cSVitaly Buka va_list args;
15437db332cSVitaly Buka va_start(args, n);
15537db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
15637db332cSVitaly Buka printva(&args, __LINE__);
15737db332cSVitaly Buka #endif
15837db332cSVitaly Buka print_shadow<T>(args, n, __FUNCTION__);
15937db332cSVitaly Buka va_end(args);
16037db332cSVitaly Buka }
16137db332cSVitaly Buka
test()16237db332cSVitaly Buka template <class T> __attribute__((noinline)) void test() {
16337db332cSVitaly Buka // Array of values we will pass into variadic functions.
16437db332cSVitaly Buka static T args[32] = {};
16537db332cSVitaly Buka
16637db332cSVitaly Buka // Poison values making the fist byte of the item shadow match the index.
16737db332cSVitaly Buka // E.g. item 3 should be poisoned as '03 ff ff ff'.
16837db332cSVitaly Buka memset(args, 0xff, sizeof(args));
16937db332cSVitaly Buka __msan_poison(args, sizeof(args));
17037db332cSVitaly Buka for (int i = 0; i < 32; ++i) {
17137db332cSVitaly Buka char *first = (char *)(&args[i]);
17237db332cSVitaly Buka *first = char(*(int *)(first)&i);
17337db332cSVitaly Buka }
17437db332cSVitaly Buka #ifdef DEBUG_VARARG_SHADOW_TEST
17537db332cSVitaly Buka __msan_print_shadow(args, sizeof(args));
17637db332cSVitaly Buka #endif
17737db332cSVitaly Buka
17837db332cSVitaly Buka // Now we will check that index, printed like 'i:03' will match
17937db332cSVitaly Buka // '0x123abc[0x123abc] 03 ff ff ff'
18037db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
18137db332cSVitaly Buka test1<T>(1, args[1]);
18237db332cSVitaly Buka // CHECK-COUNT-1: ArgShadow fn:test1 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
18337db332cSVitaly Buka
18437db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
18537db332cSVitaly Buka test1<T>(4, args[1], args[2], args[3], args[4]);
18637db332cSVitaly Buka // CHECK-COUNT-4: ArgShadow fn:test1 n:4 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
18737db332cSVitaly Buka
18837db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
18937db332cSVitaly Buka test1<T>(20, args[1], args[2], args[3], args[4], args[5], args[6], args[7],
19037db332cSVitaly Buka args[8], args[9], args[10], args[11], args[12], args[13], args[14],
19137db332cSVitaly Buka args[15], args[16], args[17], args[18], args[19], args[20]);
19237db332cSVitaly Buka // CHECK-COUNT-20: ArgShadow fn:test1 n:20 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
19337db332cSVitaly Buka
19437db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
19537db332cSVitaly Buka test2<T>(args[31], 1, args[1]);
19637db332cSVitaly Buka // CHECK-COUNT-1: ArgShadow fn:test2 n:1 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
19737db332cSVitaly Buka
19837db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
19937db332cSVitaly Buka test2<T>(args[31], 4, args[1], args[2], args[3], args[4]);
20037db332cSVitaly Buka // CHECK-COUNT-4: ArgShadow fn:test2 n:4 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
20137db332cSVitaly Buka
20237db332cSVitaly Buka memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
20337db332cSVitaly Buka test2<T>(args[31], 20, args[1], args[2], args[3], args[4], args[5], args[6],
20437db332cSVitaly Buka args[7], args[8], args[9], args[10], args[11], args[12], args[13],
20537db332cSVitaly Buka args[14], args[15], args[16], args[17], args[18], args[19],
20637db332cSVitaly Buka args[20]);
20737db332cSVitaly Buka // CHECK-COUNT-20: ArgShadow fn:test2 n:20 i:[[ARGI:[[:xdigit:]]{2}]] {{[^]]+}}] [[ARGI]]
20837db332cSVitaly Buka }
20937db332cSVitaly Buka
main(int argc,char * argv[])21037db332cSVitaly Buka int main(int argc, char *argv[]) {
21137db332cSVitaly Buka #define TEST(T...) \
21237db332cSVitaly Buka if (argc == 2 && strcmp(argv[1], #T) == 0) { \
21337db332cSVitaly Buka test<T>(); \
21437db332cSVitaly Buka return 0; \
21537db332cSVitaly Buka }
21637db332cSVitaly Buka
21737db332cSVitaly Buka TEST(char);
218*9aa88b0fSVitaly Buka // RUN: %run %t char 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
21937db332cSVitaly Buka
22037db332cSVitaly Buka TEST(int);
221*9aa88b0fSVitaly Buka // RUN: %run %t int 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
22237db332cSVitaly Buka
223faaea79eSVitaly Buka TEST(void*);
224*9aa88b0fSVitaly Buka // RUN: %run %t "void*" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
225faaea79eSVitaly Buka
22637db332cSVitaly Buka TEST(float);
227*9aa88b0fSVitaly Buka // RUN: %run %t float 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
22837db332cSVitaly Buka
22937db332cSVitaly Buka TEST(double);
230*9aa88b0fSVitaly Buka // RUN: %run %t double 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
23137db332cSVitaly Buka
23237db332cSVitaly Buka TEST(long double);
233*9aa88b0fSVitaly Buka // RUN: %run %t "long double" 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
23437db332cSVitaly Buka
23537db332cSVitaly Buka TEST(IntInt);
236*9aa88b0fSVitaly Buka // RUN: %run %t IntInt 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
23737db332cSVitaly Buka
23837db332cSVitaly Buka TEST(Int64Int64);
239*9aa88b0fSVitaly Buka // RUN: %run %t Int64Int64 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
24037db332cSVitaly Buka
24137db332cSVitaly Buka TEST(DoubleDouble);
242*9aa88b0fSVitaly Buka // RUN: %run %t DoubleDouble 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
24337db332cSVitaly Buka
24437db332cSVitaly Buka TEST(Double4);
245*9aa88b0fSVitaly Buka // RUN: %run %t Double4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
24637db332cSVitaly Buka
24737db332cSVitaly Buka TEST(DoubleFloat);
248*9aa88b0fSVitaly Buka // RUN: %run %t DoubleFloat 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
24937db332cSVitaly Buka
25037db332cSVitaly Buka TEST(LongDouble2);
251*9aa88b0fSVitaly Buka // RUN: %run %t LongDouble2 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
25237db332cSVitaly Buka
25337db332cSVitaly Buka TEST(LongDouble4);
254*9aa88b0fSVitaly Buka // RUN: %run %t LongDouble4 2>&1 | FileCheck %s --implicit-check-not="ArgShadow"
25537db332cSVitaly Buka
25637db332cSVitaly Buka return 1;
25737db332cSVitaly Buka }
258