fix(chunkenc): error out when reading unknown histogram schemas from chunks

Otherwise higher level code like PromQL needs to constantly check if it
can handle the samples.

Signed-off-by: György Krajcsovits <gyorgy.krajcsovits@grafana.com>
This commit is contained in:
György Krajcsovits 2025-09-18 09:21:03 +02:00
parent bdf547ae9c
commit 267be7dc20
No known key found for this signature in database
GPG Key ID: 47A8F9CE80FD7C7F
5 changed files with 76 additions and 0 deletions

View File

@ -54,6 +54,10 @@ func IsExponentialSchemaReserved(s int32) bool {
return s >= ExponentialSchemaMinReserved && s <= ExponentialSchemaMaxReserved
}
func IsValidSchema(s int32) bool {
return IsCustomBucketsSchema(s) || IsExponentialSchema(s)
}
// BucketCount is a type constraint for the count in a bucket, which can be
// float64 (for type FloatHistogram) or uint64 (for type Histogram).
type BucketCount interface {

View File

@ -954,6 +954,12 @@ func (it *floatHistogramIterator) Next() ValueType {
it.err = err
return ValNone
}
if !histogram.IsValidSchema(schema) {
it.err = fmt.Errorf("invalid histogram schema %d", schema)
return ValNone
}
it.schema = schema
it.zThreshold = zeroThreshold
it.pSpans, it.nSpans = posSpans, negSpans

View File

@ -14,6 +14,7 @@
package chunkenc
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
@ -1462,3 +1463,32 @@ func TestFloatHistogramEmptyBucketsWithGaps(t *testing.T) {
require.Equal(t, ValNone, it.Next())
require.NoError(t, it.Err())
}
func TestFloatHistogramIteratorFailIfSchemaInValid(t *testing.T) {
for _, schema := range []int32{-101, 101} {
t.Run(fmt.Sprintf("schema %d", schema), func(t *testing.T) {
h := &histogram.FloatHistogram{
Schema: schema,
Count: 10,
Sum: 15.0,
ZeroThreshold: 1e-100,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2},
{Offset: 1, Length: 2},
},
PositiveBuckets: []float64{1, 2, 3, 4},
}
c := NewFloatHistogramChunk()
app, err := c.Appender()
require.NoError(t, err)
_, _, _, err = app.AppendFloatHistogram(nil, 1, h, false)
require.NoError(t, err)
it := c.Iterator(nil)
require.Equal(t, ValNone, it.Next())
require.EqualError(t, it.Err(), fmt.Sprintf("invalid histogram schema %d", schema))
})
}
}

View File

@ -1077,6 +1077,12 @@ func (it *histogramIterator) Next() ValueType {
it.err = err
return ValNone
}
if !histogram.IsValidSchema(schema) {
it.err = fmt.Errorf("invalid histogram schema %d", schema)
return ValNone
}
it.schema = schema
it.zThreshold = zeroThreshold
it.pSpans, it.nSpans = posSpans, negSpans

View File

@ -14,6 +14,7 @@
package chunkenc
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
@ -1818,3 +1819,32 @@ func TestIntHistogramEmptyBucketsWithGaps(t *testing.T) {
require.Equal(t, ValNone, it.Next())
require.NoError(t, it.Err())
}
func TestHistogramIteratorFailIfSchemaInValid(t *testing.T) {
for _, schema := range []int32{-101, 101} {
t.Run(fmt.Sprintf("schema %d", schema), func(t *testing.T) {
h := &histogram.Histogram{
Schema: schema,
Count: 10,
Sum: 15.0,
ZeroThreshold: 1e-100,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2},
{Offset: 1, Length: 2},
},
PositiveBuckets: []int64{1, 2, 3, 4},
}
c := NewHistogramChunk()
app, err := c.Appender()
require.NoError(t, err)
_, _, _, err = app.AppendHistogram(nil, 1, h, false)
require.NoError(t, err)
it := c.Iterator(nil)
require.Equal(t, ValNone, it.Next())
require.EqualError(t, it.Err(), fmt.Sprintf("invalid histogram schema %d", schema))
})
}
}