[compiler-rt] f86db34 - [MSan] Move origins for overlapped memory transfer

Jianzhou Zhao via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 20 18:13:33 PST 2021


Author: Jianzhou Zhao
Date: 2021-01-21T02:11:26Z
New Revision: f86db34defc323135106dc12e9fa888003cdcbd7

URL: https://github.com/llvm/llvm-project/commit/f86db34defc323135106dc12e9fa888003cdcbd7
DIFF: https://github.com/llvm/llvm-project/commit/f86db34defc323135106dc12e9fa888003cdcbd7.diff

LOG: [MSan] Move origins for overlapped memory transfer

Reviewed-by: eugenis

Differential Revision: https://reviews.llvm.org/D94572

Added: 
    compiler-rt/test/msan/chained_origin_memmove.cpp

Modified: 
    compiler-rt/lib/msan/msan_poisoning.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/msan/msan_poisoning.cpp b/compiler-rt/lib/msan/msan_poisoning.cpp
index d121d45a1951..a92b0565cfa8 100644
--- a/compiler-rt/lib/msan/msan_poisoning.cpp
+++ b/compiler-rt/lib/msan/msan_poisoning.cpp
@@ -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) {

diff  --git a/compiler-rt/test/msan/chained_origin_memmove.cpp b/compiler-rt/test/msan/chained_origin_memmove.cpp
new file mode 100644
index 000000000000..af6935767bc9
--- /dev/null
+++ b/compiler-rt/test/msan/chained_origin_memmove.cpp
@@ -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]]


        


More information about the llvm-commits mailing list