From 7d7b9eacffbc4da97ecfb77d7d866fd5fff00d50 Mon Sep 17 00:00:00 2001 From: George Krajcsovits Date: Mon, 16 Oct 2023 16:23:26 +0200 Subject: [PATCH] Fix int32 overflow issues (#12978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a 32 bit architecture the size of int is 32 bits. Thus converting from int64, uint64 can overflow it and flip the sign. Try for yourself in playground: package main import "fmt" func main() { x := int64(0x1F0000001) y := int64(1) z := int32(x - y) // numerically this is 0x1F0000000 fmt.Printf("%v\n", z) } Prints -268435456 as if x was smaller. Followup to #12650 Signed-off-by: György Krajcsovits --- cmd/promtool/tsdb.go | 11 ++++++++++- tsdb/compact.go | 9 ++++++++- tsdb/db.go | 27 ++++++++++++++++++++++++--- tsdb/index/postingsstats.go | 11 ++++++++++- tsdb/ooo_head_read.go | 36 ++++++++++++++++++++++++++++++++---- 5 files changed, 84 insertions(+), 10 deletions(-) diff --git a/cmd/promtool/tsdb.go b/cmd/promtool/tsdb.go index 9e4500c5f..7b631000a 100644 --- a/cmd/promtool/tsdb.go +++ b/cmd/promtool/tsdb.go @@ -458,7 +458,16 @@ func analyzeBlock(ctx context.Context, path, blockID string, limit int, runExten postingInfos := []postingInfo{} printInfo := func(postingInfos []postingInfo) { - slices.SortFunc(postingInfos, func(a, b postingInfo) int { return int(b.metric) - int(a.metric) }) + slices.SortFunc(postingInfos, func(a, b postingInfo) int { + switch { + case b.metric < a.metric: + return -1 + case b.metric > a.metric: + return 1 + default: + return 0 + } + }) for i, pc := range postingInfos { if i >= limit { diff --git a/tsdb/compact.go b/tsdb/compact.go index ca3a95096..f509380f8 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -201,7 +201,14 @@ func (c *LeveledCompactor) Plan(dir string) ([]string, error) { func (c *LeveledCompactor) plan(dms []dirMeta) ([]string, error) { slices.SortFunc(dms, func(a, b dirMeta) int { - return int(a.meta.MinTime - b.meta.MinTime) + switch { + case a.meta.MinTime < b.meta.MinTime: + return -1 + case a.meta.MinTime > b.meta.MinTime: + return 1 + default: + return 0 + } }) res := c.selectOverlappingDirs(dms) diff --git a/tsdb/db.go b/tsdb/db.go index ce8ef1f9a..86cb39b8b 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -580,7 +580,14 @@ func (db *DBReadOnly) Blocks() ([]BlockReader, error) { } slices.SortFunc(loadable, func(a, b *Block) int { - return int(a.Meta().MinTime - b.Meta().MinTime) + switch { + case a.Meta().MinTime < b.Meta().MinTime: + return -1 + case a.Meta().MinTime > b.Meta().MinTime: + return 1 + default: + return 0 + } }) blockMetas := make([]BlockMeta, 0, len(loadable)) @@ -1448,7 +1455,14 @@ func (db *DB) reloadBlocks() (err error) { db.metrics.blocksBytes.Set(float64(blocksSize)) slices.SortFunc(toLoad, func(a, b *Block) int { - return int(a.Meta().MinTime - b.Meta().MinTime) + switch { + case a.Meta().MinTime < b.Meta().MinTime: + return -1 + case a.Meta().MinTime > b.Meta().MinTime: + return 1 + default: + return 0 + } }) // Swap new blocks first for subsequently created readers to be seen. @@ -1518,7 +1532,14 @@ func deletableBlocks(db *DB, blocks []*Block) map[ulid.ULID]struct{} { // Sort the blocks by time - newest to oldest (largest to smallest timestamp). // This ensures that the retentions will remove the oldest blocks. slices.SortFunc(blocks, func(a, b *Block) int { - return int(b.Meta().MaxTime - a.Meta().MaxTime) + switch { + case b.Meta().MaxTime < a.Meta().MaxTime: + return -1 + case b.Meta().MaxTime > a.Meta().MaxTime: + return 1 + default: + return 0 + } }) for _, block := range blocks { diff --git a/tsdb/index/postingsstats.go b/tsdb/index/postingsstats.go index 70622b3d2..0ad4e0857 100644 --- a/tsdb/index/postingsstats.go +++ b/tsdb/index/postingsstats.go @@ -63,6 +63,15 @@ func (m *maxHeap) push(item Stat) { } func (m *maxHeap) get() []Stat { - slices.SortFunc(m.Items, func(a, b Stat) int { return int(b.Count - a.Count) }) + slices.SortFunc(m.Items, func(a, b Stat) int { + switch { + case b.Count < a.Count: + return -1 + case b.Count > a.Count: + return 1 + default: + return 0 + } + }) return m.Items } diff --git a/tsdb/ooo_head_read.go b/tsdb/ooo_head_read.go index 198bc4f2f..c30c2b565 100644 --- a/tsdb/ooo_head_read.go +++ b/tsdb/ooo_head_read.go @@ -179,16 +179,44 @@ type chunkMetaAndChunkDiskMapperRef struct { func refLessByMinTimeAndMinRef(a, b chunkMetaAndChunkDiskMapperRef) int { if a.meta.MinTime == b.meta.MinTime { - return int(a.meta.Ref - b.meta.Ref) + switch { + case a.meta.Ref < b.meta.Ref: + return -1 + case a.meta.Ref > b.meta.Ref: + return 1 + default: + return 0 + } + } + switch { + case a.meta.MinTime < b.meta.MinTime: + return -1 + case a.meta.MinTime > b.meta.MinTime: + return 1 + default: + return 0 } - return int(a.meta.MinTime - b.meta.MinTime) } func lessByMinTimeAndMinRef(a, b chunks.Meta) int { if a.MinTime == b.MinTime { - return int(a.Ref - b.Ref) + switch { + case a.Ref < b.Ref: + return -1 + case a.Ref > b.Ref: + return 1 + default: + return 0 + } + } + switch { + case a.MinTime < b.MinTime: + return -1 + case a.MinTime > b.MinTime: + return 1 + default: + return 0 } - return int(a.MinTime - b.MinTime) } func (oh *OOOHeadIndexReader) Postings(ctx context.Context, name string, values ...string) (index.Postings, error) {