pkg/dwarf/frame: fix FrameDescriptionEntries's Append (#3433)

The current implementation has a bug to remove duplicates.
It can be implemented by using fast-slow pointers.
This commit is contained in:
gocurr 2023-07-05 23:48:33 +08:00 committed by GitHub
parent 53998cbb18
commit f016055457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 97 additions and 11 deletions

@ -91,18 +91,21 @@ func (fdes FrameDescriptionEntries) Append(otherFDEs FrameDescriptionEntries) Fr
sort.SliceStable(r, func(i, j int) bool { sort.SliceStable(r, func(i, j int) bool {
return r[i].Begin() < r[j].Begin() return r[i].Begin() < r[j].Begin()
}) })
// remove duplicates if len(r) < 2 { // fast path, no duplicates
uniqFDEs := fdes[:0] return r
for _, fde := range fdes {
if len(uniqFDEs) > 0 {
last := uniqFDEs[len(uniqFDEs)-1]
if last.Begin() == fde.Begin() && last.End() == fde.End() {
continue
}
}
uniqFDEs = append(uniqFDEs, fde)
} }
return r
// remove duplicates
slow := 1
for fast := 1; fast < len(r); fast++ {
if r[fast].Begin() != r[fast-1].Begin() || r[fast].End() != r[fast-1].End() {
if slow != fast {
r[slow] = r[fast]
}
slow++
}
}
return r[:slow]
} }
// ptrEnc represents a pointer encoding value, used during eh_frame decoding // ptrEnc represents a pointer encoding value, used during eh_frame decoding

@ -56,6 +56,89 @@ func TestFDEForPC(t *testing.T) {
} }
} }
func TestAppend(t *testing.T) {
equal := func(x, y FrameDescriptionEntries) bool {
if len(x) != len(y) {
return false
}
for i := range x {
if x[i].Begin() != y[i].Begin() || x[i].End() != y[i].End() {
return false
}
}
return true
}
var appendTests = []struct {
name string
f1 FrameDescriptionEntries
f2 FrameDescriptionEntries
want FrameDescriptionEntries
}{
{
name: "nil",
f1: nil,
f2: nil,
want: nil,
},
{
name: "one",
f1: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
},
f2: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
},
want: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
},
},
{
name: "1 item",
f1: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 50, size: 50},
},
f2: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 50, size: 50},
},
want: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 50, size: 50},
},
},
{
name: "many",
f1: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 100, size: 100},
&FrameDescriptionEntry{begin: 50, size: 50},
&FrameDescriptionEntry{begin: 50, size: 50},
&FrameDescriptionEntry{begin: 300, size: 10},
&FrameDescriptionEntry{begin: 300, size: 10},
},
f2: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 100, size: 100},
&FrameDescriptionEntry{begin: 100, size: 100},
},
want: FrameDescriptionEntries{
&FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 50, size: 50},
&FrameDescriptionEntry{begin: 100, size: 100},
&FrameDescriptionEntry{begin: 300, size: 10},
},
},
}
for _, test := range appendTests {
if got := test.f1.Append(test.f2); !equal(got, test.want) {
t.Errorf("%v.Append(%v) = %v, want %v", test.f1, test.f2, got, test.want)
}
}
}
func BenchmarkFDEForPC(b *testing.B) { func BenchmarkFDEForPC(b *testing.B) {
f, err := os.Open("testdata/frame") f, err := os.Open("testdata/frame")
if err != nil { if err != nil {