Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions interp/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,15 +323,25 @@ func (mv *memoryView) load(p pointerValue, size uint32) value {
}
v := obj.buffer.asRawValue(mv.r)
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...)
if mv.owned(p.index()) {
// A store in an owning view may change the buffer in place, so copy
// the slice to keep the loaded value independent of it.
loadedBuf = slices.Clone(loadedBuf)
}
return rawValue{buf: loadedBuf}
}

// owned reports whether this view or a parent view holds the object, so that a
// store in that view may change its buffer in place.
func (mv *memoryView) owned(index uint32) bool {
for v := mv; v != nil; v = v.parent {
if _, ok := v.objects[index]; ok {
return true
}
}
return false
}

// Store to the value behind the given pointer. This overwrites the value in the
// memory view, so that the changed value is discarded when the memory view is
// reverted. Returns true on success, false if the object to store to is
Expand Down
22 changes: 22 additions & 0 deletions interp/testdata/store.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ target triple = "x86_64--linux"
@alias.dst = global [2 x i8] zeroinitializer
@reload.buf = global [4 x i8] c"\01\02\03\04"
@reload.out = global [2 x i8] zeroinitializer
@crosscall.buf = global [4 x i8] c"\01\02\03\04"
@crosscall.out = global [2 x i8] zeroinitializer
@struct.value = global { i8, i64, { i32, i8 } } zeroinitializer

define void @runtime.initAll() unnamed_addr {
entry:
call void @overlap.init(ptr undef)
call void @alias.init(ptr undef)
call void @reload.init(ptr undef)
call void @crosscall.init(ptr undef)
call void @struct.init(ptr undef)
ret void
}
Expand Down Expand Up @@ -50,6 +53,25 @@ entry:
ret void
}

define internal void @crosscall.init(ptr %context) unnamed_addr {
entry:
; First store makes crosscall.buf writable in this memory view.
%tail = getelementptr [4 x i8], ptr @crosscall.buf, i32 0, i32 3
store i8 9, ptr %tail
; Partial load in a callee, which has its own memory view.
%val = call i16 @crosscall.get(ptr undef)
; In-place partial store in this view; this must not corrupt %val.
store i8 99, ptr @crosscall.buf
store i16 %val, ptr @crosscall.out
ret void
}

define internal i16 @crosscall.get(ptr %context) unnamed_addr {
entry:
%val = load i16, ptr @crosscall.buf
ret i16 %val
}

define internal void @struct.init(ptr %context) unnamed_addr {
entry:
%b = getelementptr { i8, i64, { i32, i8 } }, ptr @struct.value, i32 0, i32 1
Expand Down
2 changes: 2 additions & 0 deletions interp/testdata/store.out.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ target triple = "x86_64--linux"
@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"\01\02"
@crosscall.buf = local_unnamed_addr global [4 x i8] c"c\02\03\09"
@crosscall.out = local_unnamed_addr global [2 x i8] c"\01\02"
@struct.value = local_unnamed_addr global { i8, i64, { i32, i8 } } { i8 0, i64 42, { i32, i8 } { i32 0, i8 7 } }

define void @runtime.initAll() unnamed_addr {
Expand Down
16 changes: 16 additions & 0 deletions testdata/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func main() {
println(uint8SliceDst[0])
println(intSliceSrc[0])
println(intSliceDst[0])
println("loaded:", loaded)
}

type (
Expand Down Expand Up @@ -112,6 +113,21 @@ func sliceSlice(s []int, start, end int) []int {

type outside struct{}

var (
loadPair struct{ a, b int }
loaded int
)

func loadA() int { return loadPair.a }

// The value loaded by loadA must not change when init stores to loadPair.a.
func init() {
loadPair.a = 1
x := loadA()
loadPair.a = 2
loaded = x
}

func init() {
_, _ = any(0).(interface{ DoesNotExist() })
_, _ = any("").(interface{ DoesNotExist() })
Expand Down
1 change: 1 addition & 0 deletions testdata/init.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ v9: 3 2 3 4
3
5
5
loaded: 1
Loading