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:
parent
53998cbb18
commit
f016055457
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user