diff --git a/interp/memory.go b/interp/memory.go index 8b7834787..3c777d08e 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -316,10 +316,14 @@ func (mv *memoryView) load(p pointerValue, size uint32) value { panic("interp: load out of bounds") } v := obj.buffer.asRawValue(mv.r) - loadedValue := rawValue{ - buf: v.buf[p.offset() : p.offset()+size], + loadedBuf := v.buf[p.offset() : p.offset()+size] + if _, writable := mv.objects[p.index()]; writable { + // This object's buffer is owned by this view, which means a later + // store may mutate it in place (see store below). Copy the loaded + // slice so the returned value is not aliased with the live buffer. + loadedBuf = append([]uint64(nil), loadedBuf...) } - return loadedValue + return rawValue{buf: loadedBuf} } // Store to the value behind the given pointer. This overwrites the value in the @@ -356,10 +360,6 @@ func (mv *memoryView) store(v value, p pointerValue) bool { buffer := obj.buffer.asRawValue(mv.r) obj.buffer = buffer v := v.asRawValue(mv.r) - if writable { - // A partial load from this object may share the destination buffer. - v.buf = append([]uint64(nil), v.buf...) - } for i := uint32(0); i < valueLen; i++ { buffer.buf[p.offset()+i] = v.buf[i] } diff --git a/interp/testdata/store.out.ll b/interp/testdata/store.out.ll index 6c0f95052..d86e5b0cc 100644 --- a/interp/testdata/store.out.ll +++ b/interp/testdata/store.out.ll @@ -5,7 +5,7 @@ target triple = "x86_64--linux" @alias.src = local_unnamed_addr global [4 x i8] c"\05\06\07\08" @alias.dst = local_unnamed_addr global [2 x i8] c"\09\07" @reload.buf = local_unnamed_addr global [4 x i8] c"c\02\03\09" -@reload.out = local_unnamed_addr global [2 x i8] c"c\02" +@reload.out = local_unnamed_addr global [2 x i8] c"\01\02" define void @runtime.initAll() unnamed_addr { entry: