Skip to content
Open
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
19 changes: 16 additions & 3 deletions exp/api/remote/genproto/v2/symbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

package writev2

import "fmt"

// SymbolsTable implements table for easy symbol use.
type SymbolsTable struct {
strings []string
Expand Down Expand Up @@ -88,10 +90,21 @@ func (t *SymbolsTable) Reset() {
}

// DesymbolizeLabels decodes label references, with given symbols to labels.
func DesymbolizeLabels(labelRefs []uint32, symbols, buf []string) []string {
//
// The references are decoded from a remote-write request, so they are not
// trusted: an odd number of references, or a reference outside the symbols
// table, is reported as an error rather than panicking.
func DesymbolizeLabels(labelRefs []uint32, symbols, buf []string) ([]string, error) {
if len(labelRefs)%2 != 0 {
return nil, fmt.Errorf("invalid labelRefs length %v, must be even", len(labelRefs))
}
result := buf[:0]
for i := 0; i < len(labelRefs); i += 2 {
result = append(result, symbols[labelRefs[i]], symbols[labelRefs[i+1]])
nameRef, valueRef := labelRefs[i], labelRefs[i+1]
if int(nameRef) >= len(symbols) || int(valueRef) >= len(symbols) {
return nil, fmt.Errorf("labelRefs %v (name), %v (value) outside of symbols table (size %v)", nameRef, valueRef, len(symbols))
}
result = append(result, symbols[nameRef], symbols[valueRef])
}
return result
return result, nil
}
32 changes: 31 additions & 1 deletion exp/api/remote/genproto/v2/symbols_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,41 @@ func TestSymbolsTable(t *testing.T) {
ls := []string{"__name__", "qwer", "zxcv", "1234"}
encoded := s.SymbolizeLabels(ls, nil)
requireEqual(t, []uint32{1, 3, 4, 5}, encoded)
decoded := DesymbolizeLabels(encoded, s.Symbols(), nil)
decoded, err := DesymbolizeLabels(encoded, s.Symbols(), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
requireEqual(t, ls, decoded)

// Different buf.
ls = []string{"__name__", "qwer", "zxcv2222", "1234"}
encoded = s.SymbolizeLabels(ls, []uint32{1, 3, 4, 5})
requireEqual(t, []uint32{1, 3, 6, 5}, encoded)
}

func TestDesymbolizeLabelsInvalidInput(t *testing.T) {
// Label references come from a remote-write request, so malformed input has
// to be reported as an error rather than panicking the receiver.
for _, tcase := range []struct {
name string
labelRefs []uint32
symbols []string
}{
{name: "odd number of refs", labelRefs: []uint32{1}, symbols: []string{"", "a"}},
{name: "odd number of refs, longer", labelRefs: []uint32{1, 1, 1}, symbols: []string{"", "a"}},
{name: "name ref out of range", labelRefs: []uint32{9, 1}, symbols: []string{"", "a"}},
{name: "value ref out of range", labelRefs: []uint32{1, 9}, symbols: []string{"", "a"}},
{name: "refs against empty symbols", labelRefs: []uint32{0, 0}, symbols: nil},
} {
t.Run(tcase.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("unexpected panic: %v", r)
}
}()
if _, err := DesymbolizeLabels(tcase.labelRefs, tcase.symbols, nil); err == nil {
t.Fatal("expected an error, got none")
}
})
}
}
Loading