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
29 changes: 19 additions & 10 deletions pkg/sys/etw/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -935,15 +935,24 @@ func (e *EventRecord) ReadCallstackInto(offset uint16, v va.Callstack) []va.Addr
frames = (len(b) - int(offset)) / 8
}

if v != nil {
v = v[:0]
} else {
v = make([]va.Address, 0, frames)
if frames == 0 {
if v != nil {
return v[:0]
}
return []va.Address{}
}

for i := 0; i < frames; i++ {
v = append(v, va.Address(binary.LittleEndian.Uint64(b[int(offset)+i*8:])))
// size the destination without reallocating when the caller
// handed us a pooled callstack with sufficient capacity
if cap(v) >= frames {
v = v[:frames]
} else {
v = make(va.Callstack, frames)
}

// the return addresses are laid out as consecutive little-endian
// uint64 values, which is the in-memory representation of va.Address
copy(unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(v))), frames*8), b[offset:int(offset)+frames*8])
return v
}

Expand Down Expand Up @@ -987,11 +996,11 @@ func (e *EventRecord) Callstack() []va.Address {
s := (*EventExtendedItemStackTrace64)(unsafe.Pointer(uintptr(n.DataPtr)))
// number of return addresses
length := int(n.DataSize-8) / 8
addrs := make([]va.Address, length)
addresses := unsafe.Slice(&s.Address[0], length)
for i, addr := range addresses {
addrs[i] = va.Address(addr)
if length == 0 {
return nil
}
addrs := make([]va.Address, length)
copy(addrs, unsafe.Slice((*va.Address)(unsafe.Pointer(&s.Address[0])), length))
return addrs
}
return nil
Expand Down
9 changes: 9 additions & 0 deletions pkg/sys/etw/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,15 @@ func TestReadCallstackBounds(t *testing.T) {
got := ev.ReadCallstackInto(0, cs)
assert.Equal(t, []va.Address{1, 2}, got)
assert.Equal(t, 8, cap(got))

// the result must be a copy, not a view over the event payload
got[0] = 0xDEAD
assert.Equal(t, uint64(1), ev.ReadUint64(0))
assert.Equal(t, []va.Address{1, 2}, ev.ReadCallstack(0))

// a callstack with too little capacity is grown
small := make(va.Callstack, 0, 1)
assert.Equal(t, []va.Address{1, 2}, ev.ReadCallstackInto(0, small))
}

func TestCloneEmptyPayload(t *testing.T) {
Expand Down
Loading