#include <sanitizer/msan_interface.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef DEBUG_VARARG_SHADOW_TEST
__attribute__((noinline, no_sanitize("memory"))) void
printb(const void *p, size_t n, int line, int align) {
fprintf(stderr, "\n%p at line %d: \n", p, line);
for (int i = 0; i < n;) {
fprintf(stderr, "%p: ", (void *)(((uint8_t *)p) + i));
for (int j = 0; j < align; ++i, ++j)
fprintf(stderr, "%02x ", ((uint8_t *)p)[i]);
fprintf(stderr, "\n");
}
}
struct my_va_list {
# ifdef __ARM_ARCH_ISA_A64
void *stack;
void *gr_top;
void *vr_top;
int gr_offs;
int vr_offs;
# else
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
# endif
};
__attribute__((noinline, no_sanitize("memory"))) void printva(const void *p,
int line) {
my_va_list *pp = (my_va_list *)p;
# ifdef __ARM_ARCH_ISA_A64
fprintf(stderr,
"\nva %p at line %d: stack : %p\n gr_top: %p\n vr_top: %p\n gr_offs: "
"%d\n "
"vr_offs: %d\n",
p, line, pp->stack, pp->gr_top, pp->vr_top, pp->gr_offs, pp->vr_offs);
printb((char *)pp->gr_top + pp->gr_offs, -pp->gr_offs, __LINE__, 8);
printb((char *)pp->vr_top + pp->vr_offs, -pp->vr_offs, __LINE__, 16);
printb((char *)pp->stack, 256, __LINE__, 8);
# else
fprintf(stderr,
"\nva %p at line %d:\n gp_offset: %u\n fp_offset: %u\n "
"overflow_arg_area: %p\n reg_save_area: %p\n\n",
p, line, pp->gp_offset, pp->fp_offset, pp->overflow_arg_area,
pp->reg_save_area);
printb((char *)pp->reg_save_area + pp->gp_offset,
pp->fp_offset - pp->gp_offset, __LINE__, 8);
printb((char *)pp->reg_save_area + pp->fp_offset, 128, __LINE__, 16);
printb((char *)pp->overflow_arg_area, 256, __LINE__, 8);
# endif
}
__attribute__((noinline, no_sanitize("memory"))) void printtls(int line) {
uint8_t tmp[kMsanParamTlsSize];
for (int i = 0; i < kMsanParamTlsSize; ++i)
tmp[i] = __msan_va_arg_tls[i];
fprintf(stderr, "\nTLS at line %d: ", line);
for (int i = 0; i < kMsanParamTlsSize;) {
fprintf(stderr, "\n");
for (int j = 0; j < 16; ++i, ++j)
fprintf(stderr, "%02x ", tmp[i]);
}
fprintf(stderr, "\n");
}
#endif
const int kMsanParamTlsSize = 800;
extern "C" __thread uint8_t __msan_va_arg_tls[];
struct IntInt {
int a;
int b;
};
struct Int64Int64 {
int64_t a;
int64_t b;
};
struct DoubleDouble {
double a;
double b;
};
struct Double4 {
double a[4];
};
struct DoubleFloat {
double a;
float b;
};
struct LongDouble2 {
long double a[2];
};
struct LongDouble4 {
long double a[4];
};
template <class T>
__attribute__((noinline)) void print_shadow(va_list &args, int n,
const char *function) {
for (int i = 0; i < n; i++) {
fprintf(stderr, "\nArgShadow fn:%s n:%d i:%02x ", function, n, i + 1);
T arg_int = va_arg(args, T);
if (__msan_test_shadow(&arg_int, sizeof(arg_int)))
fprintf(stderr, "fake[clean] %02x", i + 1);
else
__msan_dump_shadow(&arg_int, sizeof(arg_int));
#ifdef DEBUG_VARARG_SHADOW_TEST
printb(&arg_int, sizeof(arg_int), __LINE__, 16);
#endif
}
}
template <class T> __attribute__((noinline)) void test1(int n, ...) {
#ifdef DEBUG_VARARG_SHADOW_TEST
printtls(__LINE__);
#endif
va_list args;
va_start(args, n);
#ifdef DEBUG_VARARG_SHADOW_TEST
printva(&args, __LINE__);
#endif
print_shadow<T>(args, n, __FUNCTION__);
va_end(args);
}
template <class T> __attribute__((noinline)) void test2(T t, int n, ...) {
#ifdef DEBUG_VARARG_SHADOW_TEST
printtls(__LINE__);
#endif
va_list args;
va_start(args, n);
#ifdef DEBUG_VARARG_SHADOW_TEST
printva(&args, __LINE__);
#endif
print_shadow<T>(args, n, __FUNCTION__);
va_end(args);
}
template <class T> __attribute__((noinline)) void test() {
static T args[32] = {};
memset(args, 0xff, sizeof(args));
__msan_poison(args, sizeof(args));
for (int i = 0; i < 32; ++i) {
char *first = (char *)(&args[i]);
*first = char(*(int *)(first)&i);
}
#ifdef DEBUG_VARARG_SHADOW_TEST
__msan_print_shadow(args, sizeof(args));
#endif
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test1<T>(1, args[1]);
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test1<T>(4, args[1], args[2], args[3], args[4]);
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test1<T>(20, args[1], args[2], args[3], args[4], args[5], args[6], args[7],
args[8], args[9], args[10], args[11], args[12], args[13], args[14],
args[15], args[16], args[17], args[18], args[19], args[20]);
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test2<T>(args[31], 1, args[1]);
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test2<T>(args[31], 4, args[1], args[2], args[3], args[4]);
memset(__msan_va_arg_tls, 0xee, kMsanParamTlsSize);
test2<T>(args[31], 20, args[1], args[2], args[3], args[4], args[5], args[6],
args[7], args[8], args[9], args[10], args[11], args[12], args[13],
args[14], args[15], args[16], args[17], args[18], args[19],
args[20]);
}
int main(int argc, char *argv[]) {
#define TEST(T...) \
if (argc == 2 && strcmp(argv[1], #T) == 0) { \
test<T>(); \
return 0; \
}
TEST(char);
TEST(int);
TEST(void*);
TEST(float);
TEST(double);
TEST(long double);
TEST(IntInt);
TEST(Int64Int64);
TEST(DoubleDouble);
TEST(Double4);
TEST(DoubleFloat);
TEST(LongDouble2);
TEST(LongDouble4);
return 1;
}