mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-05 05:37:10 +02:00
reproduce decoder labels memory corruption
Signed-off-by: Piotr <17101802+thampiotr@users.noreply.github.com>
This commit is contained in:
parent
7a151d8959
commit
0b3ed4020c
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -41,6 +41,7 @@ jobs:
|
||||
- uses: ./.github/promci/actions/setup_environment
|
||||
- run: go test --tags=dedupelabels ./...
|
||||
- run: go test --tags=slicelabels -race ./cmd/prometheus
|
||||
- run: go test --tags=slicelabels -race ./prompb/io/prometheus/client
|
||||
- run: go test --tags=forcedirectio -race ./tsdb/
|
||||
- run: GOARCH=386 go test ./...
|
||||
- uses: ./.github/promci/actions/check_proto
|
||||
|
@ -17,13 +17,17 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/util/pool"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -169,3 +173,74 @@ func TestMetricStreamingDecoder(t *testing.T) {
|
||||
// Expect labels and metricBytes to be static and reusable even after parsing.
|
||||
require.Equal(t, `{checksum="", path="github.com/prometheus/client_golang", version="(devel)"}`, firstMetricLset.String())
|
||||
}
|
||||
|
||||
func TestMetricStreamingDecoder_LabelsCorruption(t *testing.T) {
|
||||
lastScrapeSize := 0
|
||||
var allPreviousLabels []labels.Labels
|
||||
buffers := pool.New(128, 1024, 2, func(sz int) interface{} { return make([]byte, 0, sz) })
|
||||
builder := labels.NewScratchBuilder(0)
|
||||
for _, labelsCount := range []int{1, 2, 3, 5, 8, 5, 3, 2, 1} {
|
||||
// Get buffer from pool like in scrape.go
|
||||
b := buffers.Get(lastScrapeSize).([]byte)
|
||||
buf := bytes.NewBuffer(b)
|
||||
|
||||
// Generate some scraped data to parse
|
||||
mf := &MetricFamily{}
|
||||
data := generateMetricFamilyText(labelsCount)
|
||||
require.NoError(t, proto.UnmarshalText(data, mf))
|
||||
protoBuf, err := proto.Marshal(mf)
|
||||
require.NoError(t, err)
|
||||
sizeBuf := make([]byte, binary.MaxVarintLen32)
|
||||
sizeBufSize := binary.PutUvarint(sizeBuf, uint64(len(protoBuf)))
|
||||
buf.Write(sizeBuf[:sizeBufSize])
|
||||
buf.Write(protoBuf)
|
||||
|
||||
// Use decoder like protobufparse.go would
|
||||
b = buf.Bytes()
|
||||
d := NewMetricStreamingDecoder(b)
|
||||
require.NoError(t, d.NextMetricFamily())
|
||||
require.NoError(t, d.NextMetric())
|
||||
|
||||
// Get the labels
|
||||
builder.Reset()
|
||||
require.NoError(t, d.Label(&builder)) // <- this uses unsafe strings to create labels
|
||||
lbs := builder.Labels()
|
||||
allPreviousLabels = append(allPreviousLabels, lbs)
|
||||
|
||||
// Validate all labels seen so far remain valid and not corrupted
|
||||
for _, l := range allPreviousLabels {
|
||||
require.True(t, l.IsValid(model.LegacyValidation), "encountered corrupted labels: %v", l)
|
||||
}
|
||||
|
||||
lastScrapeSize = len(b)
|
||||
buffers.Put(b)
|
||||
}
|
||||
}
|
||||
|
||||
func generateLabels() string {
|
||||
randomName := fmt.Sprintf("instance_%d", rand.Intn(1000))
|
||||
randomValue := fmt.Sprintf("value_%d", rand.Intn(1000))
|
||||
return fmt.Sprintf(`label: <
|
||||
name: "%s"
|
||||
value: "%s"
|
||||
>`, randomName, randomValue)
|
||||
}
|
||||
|
||||
func generateMetricFamilyText(labelsCount int) string {
|
||||
randomName := fmt.Sprintf("metric_%d", rand.Intn(1000))
|
||||
randomHelp := fmt.Sprintf("Test metric to demonstrate forced corruption %d.", rand.Intn(1000))
|
||||
labels10 := ""
|
||||
for i := 0; i < labelsCount; i++ {
|
||||
labels10 += generateLabels()
|
||||
}
|
||||
return fmt.Sprintf(`name: "%s"
|
||||
help: "%s"
|
||||
type: GAUGE
|
||||
metric: <
|
||||
%s
|
||||
gauge: <
|
||||
value: 1.0
|
||||
>
|
||||
>
|
||||
`, randomName, randomHelp, labels10)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user