summaryrefslogtreecommitdiff
path: root/lib/tsan/rtl/tsan_sync.cc
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2014-07-08 20:01:12 +0000
committerDmitry Vyukov <dvyukov@google.com>2014-07-08 20:01:12 +0000
commit75e8a9117af00bc1ffe2a64c1a4232554fc506f4 (patch)
tree2dca1af5fb87230fbd7e2c5d6577f5aa186904a6 /lib/tsan/rtl/tsan_sync.cc
parent54e0edaf51707800948263a1a929cfc64f6df285 (diff)
tsan: allow memory overlap in __tsan_java_move
JVM actually moves memory between overlapping ranges. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@212560 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/tsan/rtl/tsan_sync.cc')
-rw-r--r--lib/tsan/rtl/tsan_sync.cc15
1 files changed, 12 insertions, 3 deletions
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 3462b04c2..15392c957 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -180,13 +180,22 @@ SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
}
void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
- // Here we assume that src and dst do not overlap,
- // and there are no concurrent accesses to the regions (e.g. stop-the-world).
+ // src and dst can overlap,
+ // there are no concurrent accesses to the regions (e.g. stop-the-world).
+ CHECK_NE(src, dst);
+ CHECK_NE(sz, 0);
uptr diff = dst - src;
u32 *src_meta = MemToMeta(src);
u32 *dst_meta = MemToMeta(dst);
u32 *src_meta_end = MemToMeta(src + sz);
- for (; src_meta != src_meta_end; src_meta++, dst_meta++) {
+ uptr inc = 1;
+ if (dst > src) {
+ src_meta = MemToMeta(src + sz) - 1;
+ dst_meta = MemToMeta(dst + sz) - 1;
+ src_meta_end = MemToMeta(src) - 1;
+ inc = -1;
+ }
+ for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
CHECK_EQ(*dst_meta, 0);
u32 idx = *src_meta;
*src_meta = 0;