diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-03-18 13:45:19 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-03-18 13:45:19 +0000 |
commit | 4786ed291f735699c2150f3dd4dffa62ddb89f28 (patch) | |
tree | e91de16416cd20dd6bdbcf370772c52f6bc914af | |
parent | b4a5f1c12ad45b35ebbceffc00bbc4ee788af90f (diff) |
[msan] Origin tracking with history, compiler-rt part.
Compiler-rt part of MSan implementation of advanced origin tracking,
when we record not only creation point, but all locations where
an uninitialized value was stored to memory, too.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@204152 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/msan/msan.cc | 13 | ||||
-rw-r--r-- | lib/msan/msan.h | 22 | ||||
-rw-r--r-- | lib/msan/msan_interceptors.cc | 135 | ||||
-rw-r--r-- | lib/msan/msan_interface_internal.h | 8 | ||||
-rw-r--r-- | lib/msan/msan_report.cc | 79 | ||||
-rw-r--r-- | test/msan/chained_origin.cc | 56 | ||||
-rw-r--r-- | test/msan/chained_origin_memcpy.cc | 51 |
7 files changed, 285 insertions, 79 deletions
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc index 4e9aa57bc..893553baf 100644 --- a/lib/msan/msan.cc +++ b/lib/msan/msan.cc @@ -20,6 +20,7 @@ #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_symbolizer.h" +#include "sanitizer_common/sanitizer_stackdepot.h" // ACHTUNG! No system header includes in this file. @@ -234,6 +235,13 @@ const char *GetOriginDescrIfStack(u32 id, uptr *pc) { return StackOriginDescr[id]; } +u32 ChainOrigin(u32 id, StackTrace *stack) { + uptr idx = Min(stack->size, kStackTraceMax - 1); + stack->trace[idx] = TRACE_MAKE_CHAINED(id); + u32 new_id = StackDepotPut(stack->trace, idx + 1); + return new_id; +} + } // namespace __msan // Interface. @@ -472,6 +480,11 @@ void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) { __msan_set_origin(a, size, id); } +u32 __msan_chain_origin(u32 id) { + GET_STORE_STACK_TRACE; + return ChainOrigin(id, &stack); +} + const char *__msan_get_origin_descr_if_stack(u32 id) { return GetOriginDescrIfStack(id, 0); } diff --git a/lib/msan/msan.h b/lib/msan/msan.h index 755dd7483..73734e37c 100644 --- a/lib/msan/msan.h +++ b/lib/msan/msan.h @@ -32,6 +32,12 @@ #define MEM_IS_SHADOW(mem) \ ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL) +// Chained stack trace format. +#define TRACE_MAGIC_MASK 0xFFFFFFFF00000000LLU +#define TRACE_MAKE_CHAINED(id) ((uptr)id | TRACE_MAGIC_MASK) +#define TRACE_TO_CHAINED_ID(u) ((uptr)u & (~TRACE_MAGIC_MASK)) +#define TRACE_IS_CHAINED(u) ((((uptr)u) & TRACE_MAGIC_MASK) == TRACE_MAGIC_MASK) + const int kMsanParamTlsSizeInWords = 100; const int kMsanRetvalTlsSizeInWords = 100; @@ -82,6 +88,14 @@ void ReportAtExitStatistics(); void UnpoisonParam(uptr n); void UnpoisonThreadLocalState(); +void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack); +void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack); +void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack); + +// Returns a "chained" origin id, pointing to the given stack trace followed by +// the previous origin id. +u32 ChainOrigin(u32 id, StackTrace *stack); + #define GET_MALLOC_STACK_TRACE \ StackTrace stack; \ stack.size = 0; \ @@ -90,6 +104,14 @@ void UnpoisonThreadLocalState(); StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ common_flags()->fast_unwind_on_malloc) +#define GET_STORE_STACK_TRACE \ + StackTrace stack; \ + stack.size = 0; \ + if (__msan_get_track_origins() > 1 && msan_inited) \ + GetStackTrace(&stack, common_flags()->malloc_context_size, \ + StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ + common_flags()->fast_unwind_on_malloc) + class ScopedThreadLocalStateBackup { public: ScopedThreadLocalStateBackup() { Backup(); } diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 9f99d0254..8f30d4d0e 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -208,60 +208,67 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) { INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T n = REAL(strlen)(src); char *res = REAL(strcpy)(dest, src); // NOLINT - __msan_copy_poison(dest, src, n + 1); + CopyPoison(dest, src, n + 1, &stack); return res; } INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T copy_size = REAL(strnlen)(src, n); if (copy_size < n) copy_size++; // trailing \0 char *res = REAL(strncpy)(dest, src, n); // NOLINT - __msan_copy_poison(dest, src, copy_size); + CopyPoison(dest, src, copy_size, &stack); return res; } INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T n = REAL(strlen)(src); char *res = REAL(stpcpy)(dest, src); // NOLINT - __msan_copy_poison(dest, src, n + 1); + CopyPoison(dest, src, n + 1, &stack); return res; } INTERCEPTOR(char *, strdup, char *src) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T n = REAL(strlen)(src); char *res = REAL(strdup)(src); - __msan_copy_poison(res, src, n + 1); + CopyPoison(res, src, n + 1, &stack); return res; } INTERCEPTOR(char *, __strdup, char *src) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T n = REAL(strlen)(src); char *res = REAL(__strdup)(src); - __msan_copy_poison(res, src, n + 1); + CopyPoison(res, src, n + 1, &stack); return res; } INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T copy_size = REAL(strnlen)(src, n); char *res = REAL(strndup)(src, n); - __msan_copy_poison(res, src, copy_size); + CopyPoison(res, src, copy_size, &stack); __msan_unpoison(res + copy_size, 1); // \0 return res; } INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T copy_size = REAL(strnlen)(src, n); char *res = REAL(__strndup)(src, n); - __msan_copy_poison(res, src, copy_size); + CopyPoison(res, src, copy_size, &stack); __msan_unpoison(res + copy_size, 1); // \0 return res; } @@ -279,19 +286,21 @@ INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T src_size = REAL(strlen)(src); SIZE_T dest_size = REAL(strlen)(dest); char *res = REAL(strcat)(dest, src); // NOLINT - __msan_copy_poison(dest + dest_size, src, src_size + 1); + CopyPoison(dest + dest_size, src, src_size + 1, &stack); return res; } INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; SIZE_T dest_size = REAL(strlen)(dest); SIZE_T copy_size = REAL(strnlen)(src, n); char *res = REAL(strncat)(dest, src, n); // NOLINT - __msan_copy_poison(dest + dest_size, src, copy_size); + CopyPoison(dest + dest_size, src, copy_size, &stack); __msan_unpoison(dest + dest_size + copy_size, 1); // \0 return res; } @@ -459,23 +468,26 @@ INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { // wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; wchar_t *res = REAL(wcscpy)(dest, src); - __msan_copy_poison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1)); + CopyPoison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), &stack); return res; } // wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n); INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; wchar_t *res = REAL(wmemcpy)(dest, src, n); - __msan_copy_poison(dest, src, n * sizeof(wchar_t)); + CopyPoison(dest, src, n * sizeof(wchar_t), &stack); return res; } INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; wchar_t *res = REAL(wmempcpy)(dest, src, n); - __msan_copy_poison(dest, src, n * sizeof(wchar_t)); + CopyPoison(dest, src, n * sizeof(wchar_t), &stack); return res; } @@ -489,8 +501,9 @@ INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) { INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) { ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; wchar_t *res = REAL(wmemmove)(dest, src, n); - __msan_move_poison(dest, src, n * sizeof(wchar_t)); + MovePoison(dest, src, n * sizeof(wchar_t), &stack); return res; } @@ -1336,16 +1349,44 @@ u32 get_origin_if_poisoned(uptr a, uptr size) { return 0; } -void __msan_copy_origin(void *dst, const void *src, uptr size) { +void *__msan_memcpy(void *dest, const void *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + void *res = fast_memcpy(dest, src, n); + CopyPoison(dest, src, n, &stack); + return res; +} + +void *__msan_memset(void *s, int c, SIZE_T n) { + ENSURE_MSAN_INITED(); + void *res = fast_memset(s, c, n); + __msan_unpoison(s, n); + return res; +} + +void *__msan_memmove(void *dest, const void *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + void *res = REAL(memmove)(dest, src, n); + MovePoison(dest, src, n, &stack); + return res; +} + +namespace __msan { + +void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack) { if (!__msan_get_track_origins()) return; if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return; + uptr d = (uptr)dst; uptr beg = d & ~3UL; // Copy left unaligned origin if that memory is poisoned. if (beg < d) { u32 o = get_origin_if_poisoned(beg, d - beg); - if (o) + if (o) { + if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); *(u32 *)MEM_TO_ORIGIN(beg) = o; + } beg += 4; } @@ -1353,56 +1394,56 @@ void __msan_copy_origin(void *dst, const void *src, uptr size) { // Copy right unaligned origin if that memory is poisoned. if (end > d + size) { u32 o = get_origin_if_poisoned(d + size, end - d - size); - if (o) + if (o) { + if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); *(u32 *)MEM_TO_ORIGIN(end - 4) = o; + } end -= 4; } if (beg < end) { // Align src up. uptr s = ((uptr)src + 3) & ~3UL; - fast_memcpy((void*)MEM_TO_ORIGIN(beg), (void*)MEM_TO_ORIGIN(s), end - beg); + // FIXME: factor out to msan_copy_origin_aligned + if (__msan_get_track_origins() > 1) { + u32 *src = (u32 *)MEM_TO_ORIGIN(s); + u32 *src_s = (u32 *)MEM_TO_SHADOW(s); + u32 *src_end = src + (end - beg); + u32 *dst = (u32 *)MEM_TO_ORIGIN(beg); + u32 src_o = 0; + u32 dst_o = 0; + for (; src < src_end; ++src, ++src_s, ++dst) { + if (!*src_s) continue; + if (*src != src_o) { + src_o = *src; + dst_o = ChainOrigin(src_o, stack); + } + *dst = dst_o; + } + } else { + fast_memcpy((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), + end - beg); + } } } -void __msan_copy_poison(void *dst, const void *src, uptr size) { +void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack) { if (!MEM_IS_APP(dst)) return; if (!MEM_IS_APP(src)) return; - fast_memcpy((void*)MEM_TO_SHADOW((uptr)dst), - (void*)MEM_TO_SHADOW((uptr)src), size); - __msan_copy_origin(dst, src, size); + if (src == dst) return; + internal_memmove((void *)MEM_TO_SHADOW((uptr)dst), + (void *)MEM_TO_SHADOW((uptr)src), size); + CopyOrigin(dst, src, size, stack); } -void __msan_move_poison(void *dst, const void *src, uptr size) { +void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack) { if (!MEM_IS_APP(dst)) return; if (!MEM_IS_APP(src)) return; - internal_memmove((void*)MEM_TO_SHADOW((uptr)dst), - (void*)MEM_TO_SHADOW((uptr)src), size); - __msan_copy_origin(dst, src, size); -} - -void *__msan_memcpy(void *dest, const void *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - void *res = fast_memcpy(dest, src, n); - __msan_copy_poison(dest, src, n); - return res; + fast_memcpy((void *)MEM_TO_SHADOW((uptr)dst), + (void *)MEM_TO_SHADOW((uptr)src), size); + CopyOrigin(dst, src, size, stack); } -void *__msan_memset(void *s, int c, SIZE_T n) { - ENSURE_MSAN_INITED(); - void *res = fast_memset(s, c, n); - __msan_unpoison(s, n); - return res; -} - -void *__msan_memmove(void *dest, const void *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - void *res = REAL(memmove)(dest, src, n); - __msan_move_poison(dest, src, n); - return res; -} - -namespace __msan { void InitializeInterceptors() { static int inited = 0; CHECK_EQ(inited, 0); diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h index c87b2bad2..685a8c69f 100644 --- a/lib/msan/msan_interface_internal.h +++ b/lib/msan/msan_interface_internal.h @@ -48,12 +48,6 @@ void* __msan_memset(void *s, int c, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void* __msan_memmove(void* dest, const void* src, uptr n); SANITIZER_INTERFACE_ATTRIBUTE -void __msan_copy_poison(void *dst, const void *src, uptr size); -SANITIZER_INTERFACE_ATTRIBUTE -void __msan_copy_origin(void *dst, const void *src, uptr size); -SANITIZER_INTERFACE_ATTRIBUTE -void __msan_move_poison(void *dst, const void *src, uptr size); -SANITIZER_INTERFACE_ATTRIBUTE void __msan_poison(const void *a, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __msan_poison_stack(void *a, uptr size); @@ -75,6 +69,8 @@ void __msan_set_alloca_origin(void *a, uptr size, const char *descr); SANITIZER_INTERFACE_ATTRIBUTE void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc); SANITIZER_INTERFACE_ATTRIBUTE +u32 __msan_chain_origin(u32 id); +SANITIZER_INTERFACE_ATTRIBUTE u32 __msan_get_origin(const void *a); SANITIZER_INTERFACE_ATTRIBUTE diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc index 598a13e8f..7e709f879 100644 --- a/lib/msan/msan_report.cc +++ b/lib/msan/msan_report.cc @@ -34,34 +34,53 @@ class Decorator: private __sanitizer::AnsiColorDecorator { const char *End() { return Default(); } }; -static void DescribeOrigin(u32 origin) { +static void DescribeStackOrigin(const char *so, uptr pc) { Decorator d; + char *s = internal_strdup(so); + char *sep = internal_strchr(s, '@'); + CHECK(sep); + *sep = '\0'; + Printf("%s", d.Origin()); + Printf( + " %sUninitialized value was created by an allocation of '%s%s%s'" + " in the stack frame of function '%s%s%s'%s\n", + d.Origin(), d.Name(), s, d.Origin(), d.Name(), + Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End()); + InternalFree(s); + + if (pc) { + // For some reason function address in LLVM IR is 1 less then the address + // of the first instruction. + pc += 1; + StackTrace::PrintStack(&pc, 1); + } +} + +static void DescribeOrigin(u32 origin) { VPrintf(1, " raw origin id: %d\n", origin); uptr pc; - if (const char *so = GetOriginDescrIfStack(origin, &pc)) { - char* s = internal_strdup(so); - char* sep = internal_strchr(s, '@'); - CHECK(sep); - *sep = '\0'; - Printf("%s", d.Origin()); - Printf(" %sUninitialized value was created by an allocation of '%s%s%s'" - " in the stack frame of function '%s%s%s'%s\n", - d.Origin(), d.Name(), s, d.Origin(), d.Name(), - Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End()); - InternalFree(s); - - if (pc) { - // For some reason function address in LLVM IR is 1 less then the address - // of the first instruction. - pc += 1; - StackTrace::PrintStack(&pc, 1); + while (true) { + if (const char *so = GetOriginDescrIfStack(origin, &pc)) { + DescribeStackOrigin(so, pc); + break; } - } else { + Decorator d; uptr size = 0; const uptr *trace = StackDepotGet(origin, &size); - Printf(" %sUninitialized value was created by a heap allocation%s\n", - d.Origin(), d.End()); - StackTrace::PrintStack(trace, size); + CHECK_GT(size, 0); + if (TRACE_IS_CHAINED(trace[size - 1])) { + // Linked origin. + // FIXME: copied? modified? passed through? observed? + Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(), + d.End()); + StackTrace::PrintStack(trace, size - 1); + origin = TRACE_TO_CHAINED_ID(trace[size - 1]); + } else { + Printf(" %sUninitialized value was created by a heap allocation%s\n", + d.Origin(), d.End()); + StackTrace::PrintStack(trace, size); + break; + } } } @@ -91,10 +110,18 @@ void ReportExpectedUMRNotFound(StackTrace *stack) { void ReportAtExitStatistics() { SpinMutexLock l(&CommonSanitizerReportMutex); - Decorator d; - Printf("%s", d.Warning()); - Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count); - Printf("%s", d.End()); + if (msan_report_count > 0) { + Decorator d; + Printf("%s", d.Warning()); + Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count); + Printf("%s", d.End()); + } + + StackDepotStats *stack_depot_stats = StackDepotGetStats(); + // FIXME: we want this at normal exit, too! + // FIXME: but only with verbosity=1 or something + Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids); + Printf("Stack depot mapped bytes: %zu\n", stack_depot_stats->mapped); } } // namespace __msan diff --git a/test/msan/chained_origin.cc b/test/msan/chained_origin.cc new file mode 100644 index 000000000..3b15e8890 --- /dev/null +++ b/test/msan/chained_origin.cc @@ -0,0 +1,56 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -mllvm -msan-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: not %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins -mllvm -msan-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \ +// RUN: not %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out + +#include <stdio.h> + +volatile int x, y; + +__attribute__((noinline)) +void fn_g(int a) { + x = a; +} + +__attribute__((noinline)) +void fn_f(int a) { + fn_g(a); +} + +__attribute__((noinline)) +void fn_h() { + y = x; +} + +int main(int argc, char *argv[]) { +#ifdef HEAP + int * volatile zz = new int; + int z = *zz; +#else + int volatile z; +#endif + fn_f(z); + fn_h(); + return y; +} + +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +// CHECK: {{#0 .* in main.*chained_origin.cc:37}} + +// CHECK: Uninitialized value was stored to memory at +// CHECK: {{#.* in fn_h.*chained_origin.cc:26}} +// CHECK: {{#.* in main.*chained_origin.cc:36}} + +// CHECK: Uninitialized value was stored to memory at +// CHECK: {{#.* in fn_g.*chained_origin.cc:16}} +// CHECK: {{#.* in fn_f.*chained_origin.cc:20}} +// CHECK: {{#.* in main.*chained_origin.cc:35}} + +// CHECK-STACK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main' +// CHECK-STACK: {{#0 .* in main.*chained_origin.cc:28}} + +// CHECK-HEAP: Uninitialized value was created by a heap allocation +// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:30}} diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc new file mode 100644 index 000000000..ad7f792f4 --- /dev/null +++ b/test/msan/chained_origin_memcpy.cc @@ -0,0 +1,51 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -mllvm -msan-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \ +// RUN: not %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins -mllvm -msan-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \ +// RUN: not %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out + +#include <stdio.h> +#include <string.h> + +int xx[10000]; +int yy[10000]; +volatile int idx = 30; + +__attribute__((noinline)) +void fn_g(int a, int b) { + xx[idx] = a; xx[idx + 10] = b; +} + +__attribute__((noinline)) +void fn_f(int a, int b) { + fn_g(a, b); +} + +__attribute__((noinline)) +void fn_h() { + memcpy(&yy, &xx, sizeof(xx)); +} + +int main(int argc, char *argv[]) { + int volatile z1; + int volatile z2; + fn_f(z1, z2); + fn_h(); + return yy[idx + OFFSET]; +} + +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +// CHECK: {{#0 .* in main .*chained_origin_memcpy.cc:36}} + +// CHECK: Uninitialized value was stored to memory at +// CHECK: {{#.* in fn_h.*chained_origin_memcpy.cc:28}} + +// CHECK: Uninitialized value was stored to memory at +// CHECK: {{#.* in fn_g.*chained_origin_memcpy.cc:.*}} +// CHECK: {{#.* in fn_f.*chained_origin_memcpy.cc:23}} + +// CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the stack frame of function 'main' +// CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the stack frame of function 'main' +// CHECK: {{#0 .* in main.*chained_origin_memcpy.cc:31}} |