diff --git a/pkg/textparse/openmetricsparse.go b/pkg/textparse/openmetricsparse.go index 853076f1d..708ae5dd9 100644 --- a/pkg/textparse/openmetricsparse.go +++ b/pkg/textparse/openmetricsparse.go @@ -20,7 +20,6 @@ import ( "io" "math" "sort" - "strconv" "strings" "unicode/utf8" @@ -268,7 +267,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) { if t2 != tValue { return EntryInvalid, parseError("expected value after metric", t) } - if p.val, err = strconv.ParseFloat(yoloString(p.l.buf()[1:]), 64); err != nil { + if p.val, err = parseFloat(yoloString(p.l.buf()[1:])); err != nil { return EntryInvalid, err } // Ensure canonical NaN value. @@ -283,7 +282,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) { p.hasTS = true var ts float64 // A float is enough to hold what we need for millisecond resolution. - if ts, err = strconv.ParseFloat(yoloString(p.l.buf()[1:]), 64); err != nil { + if ts, err = parseFloat(yoloString(p.l.buf()[1:])); err != nil { return EntryInvalid, err } p.ts = int64(ts * 1000) diff --git a/pkg/textparse/openmetricsparse_test.go b/pkg/textparse/openmetricsparse_test.go index f8c792588..6bb6bdfab 100644 --- a/pkg/textparse/openmetricsparse_test.go +++ b/pkg/textparse/openmetricsparse_test.go @@ -370,6 +370,22 @@ func TestOpenMetricsParseErrors(t *testing.T) { input: "empty_label_name{=\"\"} 0", err: "expected label name or left brace, got \"EQUAL\"", }, + { + input: "foo 1_2\n", + err: "unsupported character in float", + }, + { + input: "foo 0x1p-3\n", + err: "unsupported character in float", + }, + { + input: "foo 0x1P-3\n", + err: "unsupported character in float", + }, + { + input: "foo 0 1_2\n", + err: "unsupported character in float", + }, } for i, c := range cases { diff --git a/pkg/textparse/promparse.go b/pkg/textparse/promparse.go index f05b87abd..2ecb04bff 100644 --- a/pkg/textparse/promparse.go +++ b/pkg/textparse/promparse.go @@ -332,7 +332,7 @@ func (p *PromParser) Next() (Entry, error) { if t2 != tValue { return EntryInvalid, parseError("expected value after metric", t) } - if p.val, err = strconv.ParseFloat(yoloString(p.l.buf()), 64); err != nil { + if p.val, err = parseFloat(yoloString(p.l.buf())); err != nil { return EntryInvalid, err } // Ensure canonical NaN value. @@ -409,3 +409,11 @@ var helpReplacer = strings.NewReplacer( func yoloString(b []byte) string { return *((*string)(unsafe.Pointer(&b))) } + +func parseFloat(s string) (float64, error) { + // Keep to pre-Go 1.13 float formats. + if strings.ContainsAny(s, "pP_") { + return 0, fmt.Errorf("unsupported character in float") + } + return strconv.ParseFloat(s, 64) +} diff --git a/pkg/textparse/promparse_test.go b/pkg/textparse/promparse_test.go index 7bfa36fc0..9b62079d5 100644 --- a/pkg/textparse/promparse_test.go +++ b/pkg/textparse/promparse_test.go @@ -249,6 +249,22 @@ func TestPromParseErrors(t *testing.T) { input: "empty_label_name{=\"\"} 0", err: "expected label name, got \"EQUAL\"", }, + { + input: "foo 1_2\n", + err: "unsupported character in float", + }, + { + input: "foo 0x1p-3\n", + err: "unsupported character in float", + }, + { + input: "foo 0x1P-3\n", + err: "unsupported character in float", + }, + { + input: "foo 0 1_2\n", + err: "expected next entry after timestamp, got \"MNAME\"", + }, } for i, c := range cases {