diff --git a/pkg/phlaredb/symdb/rewriter.go b/pkg/phlaredb/symdb/rewriter.go index 61502e04c9..9f35438481 100644 --- a/pkg/phlaredb/symdb/rewriter.go +++ b/pkg/phlaredb/symdb/rewriter.go @@ -128,6 +128,10 @@ func (p *partitionRewriter) populateUnresolved(stacktraceIDs []uint32) error { for unresolvedLocs.Next() { location := p.src.Locations[unresolvedLocs.At()] location.MappingId = p.mappings.tryLookup(location.MappingId) + if len(p.src.Functions) == 0 { + location.Line = nil + continue + } for j, line := range location.Line { location.Line[j].FunctionId = p.functions.tryLookup(line.FunctionId) } diff --git a/pkg/pprof/pprof.go b/pkg/pprof/pprof.go index 3e1f49ebed..c07171d72e 100644 --- a/pkg/pprof/pprof.go +++ b/pkg/pprof/pprof.go @@ -1313,6 +1313,9 @@ func sanitizeProfile(p *profilev1.Profile) { }) // Check locations again, verifying that all functions are valid. p.Location = slices.RemoveInPlace(p.Location, func(x *profilev1.Location, _ int) bool { + if len(x.Line) == 0 && x.Address == 0 { + return true + } for _, line := range x.Line { if line.FunctionId = t[line.FunctionId]; line.FunctionId == 0 { return true diff --git a/pkg/pprof/pprof_test.go b/pkg/pprof/pprof_test.go index fa001b561e..d03e9cddea 100644 --- a/pkg/pprof/pprof_test.go +++ b/pkg/pprof/pprof_test.go @@ -348,9 +348,9 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{3, 2, 1}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 3, MappingId: 5}, - {Id: 2, MappingId: 0}, + {Id: 1, MappingId: 1, Address: 1}, + {Id: 3, MappingId: 5, Address: 2}, + {Id: 2, MappingId: 0, Address: 3}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -361,8 +361,8 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{2, 1}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 2, MappingId: 2}, + {Id: 1, MappingId: 1, Address: 1}, + {Id: 2, MappingId: 2, Address: 3}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -379,14 +379,14 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{5}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 0, MappingId: 0}, + {Id: 1, MappingId: 1, Address: 0xa}, + {Id: 0, MappingId: 0, Address: 0xa}, }, }, expected: &profilev1.Profile{ Sample: []*profilev1.Sample{}, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, + {Id: 1, MappingId: 1, Address: 0xa}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -513,10 +513,13 @@ func Test_sanitize_fixtures(t *testing.T) { case filepath.Ext(path) == ".txt": return nil case d.IsDir(): - if d.Name() == "fuzz" { + switch d.Name() { + case "fuzz": + case "malformed": return fs.SkipDir + default: + return nil } - return nil } t.Run(path, func(t *testing.T) { @@ -1604,3 +1607,26 @@ func Test_SetProfileMetadata(t *testing.T) { } require.Equal(t, expected.String(), p.String()) } + +func Test_pprof_zero_addr_no_line_locations(t *testing.T) { + b, err := OpenFile("testdata/malformed/no_addr_no_line.pb.gz") + require.NoError(t, err) + + var found bool + for _, loc := range b.Location { + if len(loc.Line) == 0 && loc.Address == 0 { + found = true + break + } + } + if !found { + t.Fatal("invalid fixture") + } + + b.Normalize() + for _, loc := range b.Location { + if len(loc.Line) == 0 && loc.Address == 0 { + t.Fatal("found location without lines and address") + } + } +} diff --git a/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz b/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz new file mode 100644 index 0000000000..7c13dc4431 Binary files /dev/null and b/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz differ