[bug] - Crashes while trying to decode a recording of perf DWARF data
Perf recording taking on arm64 (Apple M1, ubuntu VM in VMWare). May affect other platforms.
To reproduce, just take a perf recording with --call-graph=dwarf:
perf record --call-graph dwarf
Then try to dump it:
~/go/bin/perfdump -i perf.data
events:
0x400012c000={Event:EventSoftwareCPUClock SamplePeriod:0 SampleFreq:4000 SampleFormat:Addr|CPU|Callchain|DataSrc|IP|Period|RegsUser|StackUser|TID|Time ReadFormat:ID Flags:AuxOutput|Comm|CommExec|Disabled|ExcludeCallchainUser|ExcludeGuest|Freq|Inherit|Ksymbol|Mmap|MmapData|MmapInodeData|SampleIDAll|Task Precise:EventPrecisionZeroSkip WakeupEvents:0 WakeupWatermark:0 BranchSampleType:0 SampleRegsUser:8589934591 SampleStackUser:8192 SampleRegsIntr:0 AuxWatermark:0 SampleMaxStack:0}
build IDs:
...
hostname: ubuntu
OS release: 5.4.0-92-generic
version: 5.4.157
arch: aarch64
CPUs online: 4
CPUs available: 4
CPU desc:
CPUID:
total memory: 2070073344
cmdline: [/usr/lib/linux-tools-5.4.0-92/perf record --call-graph dwarf]
core groups: [0-3]
thread groups: [0 1 2 3]
NUMA nodes: [{0 2070073344 387358720 0-3}]
PMU mappings: map[1:software 2:tracepoint 5:breakpoint 6:kprobe 7:uprobe]
groups: []
panic: runtime error: index out of range [7] with length 0
goroutine 1 [running]:
encoding/binary.littleEndian.Uint64(...)
/usr/local/go/src/encoding/binary/binary.go:77
github.com/aclements/go-perf/perffile.(*bufDecoder).u64(...)
/root/go/pkg/mod/github.com/aclements/[email protected]/perffile/bufdecoder.go:48
github.com/aclements/go-perf/perffile.(*Records).parseSample(0x4000154000, 0x4000069998, 0x40001e7db0, 0x90?)
/root/go/pkg/mod/github.com/aclements/[email protected]/perffile/records.go:610 +0xaa4
github.com/aclements/go-perf/perffile.(*Records).Next(0x4000154000)
/root/go/pkg/mod/github.com/aclements/[email protected]/perffile/records.go:148 +0x508
github.com/aclements/go-perf/perffile.(*File).Records(0x4000128000, 0x400011a008?)
/root/go/pkg/mod/github.com/aclements/[email protected]/perffile/reader.go:350 +0x298
main.main()
/root/go/pkg/mod/github.com/aclements/[email protected]/cmd/perfdump/main.go:77 +0x750
Actual crash is caused by https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/encoding/binary/binary.go;l=77 so I guess that the issue is that it is passed an empty buffer (a bit surprising they don't check boundaries in stdlib...)
Maybe a guard can be placed on https://github.com/aclements/go-perf/blob/cadabe6d386a5472159d9cb2945d2115f6ae77d7/perffile/bufdecoder.go#L48 or in https://github.com/aclements/go-perf/blob/cadabe6d386a5472159d9cb2945d2115f6ae77d7/perffile/records.go#L609-L611
The following patch avoids the crash:
diff --git a/perffile/bufdecoder.go b/perffile/bufdecoder.go
index fcb5966..79425fa 100644
--- a/perffile/bufdecoder.go
+++ b/perffile/bufdecoder.go
@@ -45,6 +45,9 @@ func (b *bufDecoder) i32() int32 {
}
func (b *bufDecoder) u64() uint64 {
+ if len(b.buf) < 8 {
+ return 0
+ }
x := b.order.Uint64(b.buf)
b.buf = b.buf[8:]
return x
FYI it is not an ARM specific bug, verified on amd64 as well