forked from OSchip/llvm-project
[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. llvm-svn: 204152
This commit is contained in:
parent
302964ee92
commit
412d973980
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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,55 +1349,11 @@ u32 get_origin_if_poisoned(uptr a, uptr size) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __msan_copy_origin(void *dst, const void *src, uptr size) {
|
||||
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)
|
||||
*(u32 *)MEM_TO_ORIGIN(beg) = o;
|
||||
beg += 4;
|
||||
}
|
||||
|
||||
uptr end = (d + size + 3) & ~3UL;
|
||||
// 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)
|
||||
*(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);
|
||||
}
|
||||
}
|
||||
|
||||
void __msan_copy_poison(void *dst, const void *src, uptr size) {
|
||||
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);
|
||||
}
|
||||
|
||||
void __msan_move_poison(void *dst, const void *src, uptr size) {
|
||||
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();
|
||||
GET_STORE_STACK_TRACE;
|
||||
void *res = fast_memcpy(dest, src, n);
|
||||
__msan_copy_poison(dest, src, n);
|
||||
CopyPoison(dest, src, n, &stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1397,12 +1366,84 @@ void *__msan_memset(void *s, int c, SIZE_T n) {
|
|||
|
||||
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);
|
||||
__msan_move_poison(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 (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
|
||||
*(u32 *)MEM_TO_ORIGIN(beg) = o;
|
||||
}
|
||||
beg += 4;
|
||||
}
|
||||
|
||||
uptr end = (d + size + 3) & ~3UL;
|
||||
// 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 (__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;
|
||||
// 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 MovePoison(void *dst, const void *src, uptr size, StackTrace *stack) {
|
||||
if (!MEM_IS_APP(dst)) return;
|
||||
if (!MEM_IS_APP(src)) return;
|
||||
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 CopyPoison(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);
|
||||
CopyOrigin(dst, src, size, stack);
|
||||
}
|
||||
|
||||
void InitializeInterceptors() {
|
||||
static int inited = 0;
|
||||
CHECK_EQ(inited, 0);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
|
@ -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}}
|
Loading…
Reference in New Issue