stream: consumer-group counters can exceed INT64_MAX and break clients decoding RESP integers as signed
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- cpp, redis
調査の方向性
src/types/redis_stream.cc から開始し、記載されている consumer-group の減算パスを追跡してから、src/server/redis_reply.h と XINFO の stream/group/consumer serializer を調査します。XPENDING が summary count をどのように取得するかを確認し、可能な saturation の方法と emit 側での処理方法を比較します。残っている unsigned counters と timestamp deltas が signed 64-bit range 外の RESP integers を生成できず、実装前に動作について合意できていれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
Several Redis-stream consumer-group counters are stored as uint64_t and emitted directly via redis::Integer (std::to_string, src/server/redis_reply.h). If any of them holds a value above INT64_MAX, the reply is a decimal like :18446744073709551615\r\n, which clients that decode RESP : integers as signed 64-bit (e.g. the Rust fred client) fail to parse — the connection is dropped/poisoned rather than returning group info.
PR #3578 fixes the two concrete instances we hit in production. This issue tracks the remaining, related hardening so it can be discussed before a broader patch (per the contributing guide's "discuss first / prefer focused patches").
Already addressed by #3578
XAUTOCLAIMdeleting a dangling PEL entry without decrementingpending_number(counter drifts up, later wraps).XINFO GROUPSlagwrapping whenentries_read > entries_added(unsigned subtraction).
Remaining, same failure class
-
Non-saturating
pending_numberdecrements. After #3578,AutoClaimis the only saturating decrement; these still subtract unconditionally, so any invariant break wraps a client-visibleuint64counter (allsrc/types/redis_stream.cc):DeleteConsumer(XGROUP DELCONSUMER):group.pending_number -= deleted_pel— cross-level (subtracts a consumer's count from the group's count), highest risk.DeletePelEntries(XACK):group.pending_number -= *acknowledgedandconsumer.pending_number -= ack_count.ClaimPelEntries(XCLAIM):original_consumer.pending_number -= 1.
-
lagcan exceedINT64_MAXeven without a wrap.entries_addedis settable to anyuint64viaXSETID ... ENTRIESADDED n, so a correctly-computedlag = entries_added - entries_readcan be a legitimate value> INT64_MAXthatCheckLagValidpasses through to the reply. #3578's guard only covers theentries_read > entries_addedwrap. -
No emit-side clamp for already-corrupt data. #3578 stops future drift but doesn't repair or clamp existing values, and other unsigned fields are emitted raw: group/consumer
pending_number(XINFO GROUPS/CONSUMERS),entries-added(XINFO STREAM), and theidle/inactivetimestamp deltas (now - stored_ts, which wrap under clock skew / a future ts injected via XCLAIM). (The XPENDING summary count appears to be recomputed live from the PEL scan — worth confirming whether it reads the cached counter on any path.)
Suggested direction
- Make all consumer-group counter decrements saturating (
x >= n ? x - n : 0), matching #3578's AutoClaim decrement. - Either treat
lag > INT64_MAXas unknown (nil, via the existingUINT64_MAXsentinel) inCheckLagValid, or add an emit-side clamp helper (min(v, INT64_MAX)) applied to the counter/timestamp serializations so the wire value is always within i64 for strict clients. Redis already treats these as signed, so clamping is behavior-compatible.
Happy to send a PR once there's agreement on the preferred shape (per-site saturation vs. a shared emit-side clamp).
AI assistance: the analysis behind this issue was done with AI help; I've reviewed and verified the findings against the source.
- 主要言語
- C++
- スター
- 4.5k
- フォーク
- 689
- 平均マージ
- 1日 22時間
- マージ済み PR(30日)
- 37
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートなし
- コントリビューションガイドなし
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
apache/kvrocks のほかの issue
-
HSETEXPIRE with an overflowing TTL returns OK and deletes the whole hash対応中かも @anubhavgupta121 が 20 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
メンテナーはふだん 1 日以内に返信
-
`JSON.STRAPPEND` with non JSON value crashes the server対応中かも @ggyuchive が今日担当しました。 オープンbug
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
A blocked client that is woken but loses the element to another client is never woken again対応中かも @ggyuchive が 1 日前に担当しました。 オープンbug
難易度 4/5 1〜2日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
-
SSCAN, HSCAN, ZSCAN don't finish when an empty-string member is returned at the end of a page対応中かも @ggyuchive が 3 日前に担当しました。 オープンbug
難易度 3/5 1〜2日 初心者へのやさしさ 77/100
メンテナーはふだん 1 日以内に返信
-
`GEOSEARCH` / `GEORADIUS` with a negative radius hangs対応中かも @ggyuchive が 9 日前に担当しました。 オープンbug
難易度 3/5 1〜2日 初心者へのやさしさ 25/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
難易度 1/5 1〜3時間 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
godotengine/godot#125272 ·
メンテナーはふだん 1 日以内に返信
-
bug impact: performance priority: med review: 2026-11 severity: med
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
mgradwohl/ModernLife#67 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
games-on-whales/wolf#569 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
cloudflare/workerd#8290 ·
メンテナーはふだん 1 日以内に返信