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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## master / unreleased
* [BUGFIX] Querier: Fix a panic in the active query tracker's `trimStringByBytes` when a request field consists only of UTF-8 continuation bytes (e.g. an unvalidated `match[]`/`query` value), which caused the rune-boundary scan to underflow and crash the querier. #7729
* [FEATURE] Engine: Add `-querier.selector-batch-size` and `-ruler.selector-batch-size` flags to configure series batching in the Thanos promQL engine. 0 disables batching. #7763
* [CHANGE] Querier: Make query time range configurations per-tenant: `query_ingesters_within`, `query_store_after`, and `shuffle_sharding_ingesters_lookback_period`. Uses `model.Duration` instead of `time.Duration` to support serialization but has minimum unit of 1ms (nanoseconds/microseconds not supported). #7160
* [CHANGE] Cache: Setting `-blocks-storage.bucket-store.metadata-cache.bucket-index-content-ttl` to 0 will disable the bucket-index cache. #7446
Expand Down
5 changes: 4 additions & 1 deletion pkg/util/request_tracker/request_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ func trimStringByBytes(str string, size int) string {
bytesStr := []byte(str)
trimIndex := len(bytesStr)
if size < len(bytesStr) {
for !utf8.RuneStart(bytesStr[size]) {
// Scan backwards to a rune boundary. Bound the scan at size > 0: if the
// string has no rune start (e.g. only UTF-8 continuation bytes) the loop
// must not underflow past zero, which would panic on bytesStr[-1].
for size > 0 && !utf8.RuneStart(bytesStr[size]) {
size--
}
trimIndex = size
Expand Down
17 changes: 17 additions & 0 deletions pkg/util/request_tracker/request_tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,20 @@ func TestRangedQueryExtractorMultiByteTruncation(t *testing.T) {
assert.True(t, utf8.Valid(entry), "entry should be valid UTF-8")
})
}

// TestTrimForJsonMarshalContinuationBytes reproduces cortexproject/cortex#7729:
// when the string consists only of UTF-8 continuation bytes (0x80-0xBF) there is
// no rune start to scan back to, so the backwards scan in trimStringByBytes
// underflows past zero and panics with index out of range [-1]. The fix bounds
// the scan at size > 0.
func TestTrimForJsonMarshalContinuationBytes(t *testing.T) {
// 1200 continuation bytes (0x80) with a truncation size below the length.
continuation := strings.Repeat("\x80", 1200)

require.NotPanics(t, func() {
out := trimForJsonMarshal(continuation, 900)
// Result must always be valid UTF-8 (no partial runes).
assert.True(t, utf8.ValidString(out), "result should be valid UTF-8")
assert.LessOrEqual(t, len(out), len(continuation))
})
}