mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
interp: fix partial store aliasing with previously loaded values
The optimization to skip cloning the destination object on partial stores when the buffer is already owned by the current memory view mutated obj.buffer.buf in place. The previous v.buf clone only handled the case where the store value itself aliased that buffer; it did not cover the more common case where an earlier partial load had returned a slice into the same buffer. The in-place store would then corrupt the previously loaded value, breaking code such as cloudflare/bn256 where the gfP arithmetic loads, computes, and stores within the same global during package initialization. Fix this in load instead: when the source object is owned by the current memory view, copy the loaded slice so the returned value is independent of the live buffer. The v.buf clone in store is no longer needed and is removed. Updates the regression test added in the previous commit to reflect the corrected behavior.
This commit is contained in:
+7
-7
@@ -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]
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user