forked from OSchip/llvm-project
[MSan] Move origins for overlapped memory transfer
Reviewed-by: eugenis Differential Revision: https://reviews.llvm.org/D94572
This commit is contained in:
parent
bff389120f
commit
f86db34def
|
@ -94,23 +94,98 @@ void CopyOrigin(const void *dst, const void *src, uptr size,
|
|||
}
|
||||
}
|
||||
|
||||
void ReverseCopyOrigin(const void *dst, const void *src, uptr size,
|
||||
StackTrace *stack) {
|
||||
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src))
|
||||
return;
|
||||
|
||||
uptr d = (uptr)dst;
|
||||
uptr end = (d + size) & ~3UL;
|
||||
|
||||
// Copy right unaligned origin if that memory is poisoned.
|
||||
if (end < d + size) {
|
||||
u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
|
||||
if (o) {
|
||||
if (__msan_get_track_origins() > 1)
|
||||
o = ChainOrigin(o, stack);
|
||||
*(u32 *)MEM_TO_ORIGIN(end) = o;
|
||||
}
|
||||
}
|
||||
|
||||
uptr beg = d & ~3UL;
|
||||
|
||||
if (beg + 4 < end) {
|
||||
// Align src up.
|
||||
uptr s = ((uptr)src + 3) & ~3UL;
|
||||
if (__msan_get_track_origins() > 1) {
|
||||
u32 *src = (u32 *)MEM_TO_ORIGIN(s + end - beg - 4);
|
||||
u32 *src_s = (u32 *)MEM_TO_SHADOW(s + end - beg - 4);
|
||||
u32 *src_begin = (u32 *)MEM_TO_ORIGIN(s);
|
||||
u32 *dst = (u32 *)MEM_TO_ORIGIN(end - 4);
|
||||
u32 src_o = 0;
|
||||
u32 dst_o = 0;
|
||||
for (; src >= src_begin; --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 {
|
||||
REAL(memmove)
|
||||
((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), end - beg - 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy left unaligned origin if that memory is poisoned.
|
||||
if (beg < d) {
|
||||
u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d);
|
||||
if (o) {
|
||||
if (__msan_get_track_origins() > 1)
|
||||
o = ChainOrigin(o, stack);
|
||||
*(u32 *)MEM_TO_ORIGIN(beg) = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveOrigin(const void *dst, const void *src, uptr size,
|
||||
StackTrace *stack) {
|
||||
// If destination origin range overlaps with source origin range, move
|
||||
// origins by coping origins in a reverse order; otherwise, copy origins in
|
||||
// a normal order.
|
||||
uptr src_aligned_beg = reinterpret_cast<uptr>(src) & ~3UL;
|
||||
uptr src_aligned_end = (reinterpret_cast<uptr>(src) + size) & ~3UL;
|
||||
uptr dst_aligned_beg = reinterpret_cast<uptr>(dst) & ~3UL;
|
||||
if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)
|
||||
return ReverseCopyOrigin(dst, src, size, stack);
|
||||
return CopyOrigin(dst, src, size, stack);
|
||||
}
|
||||
|
||||
void MoveShadowAndOrigin(const 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;
|
||||
// MoveOrigin transfers origins by refering to their shadows. So we
|
||||
// need to move origins before moving shadows.
|
||||
if (__msan_get_track_origins())
|
||||
MoveOrigin(dst, src, size, stack);
|
||||
REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
|
||||
(void *)MEM_TO_SHADOW((uptr)src), size);
|
||||
if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
|
||||
}
|
||||
|
||||
void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
|
||||
StackTrace *stack) {
|
||||
if (!MEM_IS_APP(dst)) return;
|
||||
if (!MEM_IS_APP(src)) return;
|
||||
// Because origin's range is slightly larger than app range, memcpy may also
|
||||
// cause overlapped origin ranges.
|
||||
REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
|
||||
(void *)MEM_TO_SHADOW((uptr)src), size);
|
||||
if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
|
||||
if (__msan_get_track_origins())
|
||||
MoveOrigin(dst, src, size, stack);
|
||||
}
|
||||
|
||||
void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \
|
||||
// RUN: not %run %t >%t.out 2>&1
|
||||
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 --check-prefix=CHECK-%short-stack < %t.out
|
||||
|
||||
// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \
|
||||
// RUN: not %run %t >%t.out 2>&1
|
||||
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 --check-prefix=CHECK-%short-stack < %t.out
|
||||
|
||||
// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \
|
||||
// RUN: not %run %t >%t.out 2>&1
|
||||
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 --check-prefix=CHECK-%short-stack < %t.out
|
||||
|
||||
// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \
|
||||
// RUN: not %run %t >%t.out 2>&1
|
||||
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 --check-prefix=CHECK-%short-stack < %t.out
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int xx[10000];
|
||||
volatile int idx = 30;
|
||||
|
||||
__attribute__((noinline)) void fn_g(int a, int b) {
|
||||
xx[idx + OFFSET] = OFFSET == 0 ? a : b;
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void fn_f(int a, int b) {
|
||||
fn_g(a, b);
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void fn_h() {
|
||||
memmove(&xx[25], &xx, 7500);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int volatile z1;
|
||||
int volatile z2;
|
||||
fn_f(z1, z2);
|
||||
fn_h();
|
||||
return xx[25 + idx + OFFSET];
|
||||
}
|
||||
|
||||
// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
|
||||
// CHECK: {{#0 .* in main .*chained_origin_memmove.cpp:}}[[@LINE-4]]
|
||||
|
||||
// CHECK: Uninitialized value was stored to memory at
|
||||
// CHECK-FULL-STACK: {{#1 .* in fn_h.*chained_origin_memmove.cpp:}}[[@LINE-15]]
|
||||
// CHECK-SHORT-STACK: {{#0 .* in __msan_memmove.*msan_interceptors.cpp:}}
|
||||
|
||||
// CHECK: Uninitialized value was stored to memory at
|
||||
// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memmove.cpp:}}[[@LINE-27]]
|
||||
// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memmove.cpp:}}[[@LINE-24]]
|
||||
// CHECK-SHORT-STACK: {{#0 .* in fn_g.*chained_origin_memmove.cpp:}}[[@LINE-29]]
|
||||
|
||||
// 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_memmove.cpp:}}[[@LINE-22]]
|
Loading…
Reference in New Issue