summaryrefslogtreecommitdiff
path: root/lib/msan/msan_interceptors.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msan/msan_interceptors.cc')
-rw-r--r--lib/msan/msan_interceptors.cc38
1 files changed, 32 insertions, 6 deletions
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index c200e6c5..849949d3 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -1278,15 +1278,41 @@ void __msan_clear_and_unpoison(void *a, uptr size) {
fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
}
+u32 get_origin_if_poisoned(uptr a, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return *(uptr *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ 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 = MEM_TO_ORIGIN(dst);
- uptr s = MEM_TO_ORIGIN(src);
- uptr beg = d & ~3UL; // align down.
- uptr end = (d + size + 3) & ~3UL; // align up.
- s = s & ~3UL; // align down.
- fast_memcpy((void*)beg, (void*)s, end - beg);
+ 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)
+ *(uptr *)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)
+ *(uptr *)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) {