Fix integer underflow in BITCOUNT ... BIT byte-boundary mask - #1994
Merged
Conversation
Contributor
There was a problem hiding this comment.
🟢 Ready to approve
The fix is narrowly scoped, matches the described root cause, and is covered by a focused regression test plus an updated expectation aligned to the documented offset semantics.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR fixes a correctness bug in Garnet’s bitmap BITCOUNT ... BIT implementation (BitmapManagerBitCount.cs) where ranges ending exactly on a byte boundary could return a non-zero count for bits that are actually unset (due to an integer underflow in the boundary mask calculation).
Changes:
- Fixes the inclusive “right bit index” calculation for BIT-mode ranges that end on a byte boundary.
- Adds a regression test validating single-bit and boundary-ending BIT ranges on a
0x80payload. - Updates a long negative-offset parsing expectation that previously passed only because of the underflow behavior.
File summaries
| File | Description |
|---|---|
| test/standalone/Garnet.test.complexstring/GarnetBitmapTests.cs | Adds a targeted regression test for the byte-boundary underflow and updates the long negative-offset BITCOUNT expectation. |
| libs/server/Resp/Bitmap/BitmapManagerBitCount.cs | Corrects rightBitIndex computation to avoid wrapping to 0 on endOffset % 8 == 7, preventing mask underflow. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Low
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
TedHartMS
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes an integer underflow in
BITCOUNT ... BIT(BitmapManagerBitCount.cs) that caused non-zero counts to be returned for unset bits whenever a BIT-mode range ended on a byte boundary (endOffset % 8 == 7).Root cause
BitIndexCount(byte* value, long startOffset, long endOffset)computed the inclusive right bit index as:When this wraps to
0, the innerBitIndexCount(byte, start, end)buildsmask = (byte)((1<<0) - (1<<start)), a wrapping byte-mask underflow (e.g.0x81). AND-ed with the bit-reversed payload this reports set bits that are not set. For byte0x80,BITCOUNT key 7 7 BITreturned1even thoughGETBIT key 7 == 0.Fix
Use the same formula already used (correctly) in
BitmapManagerBitPos.cs:Tests
BitmapBitCountBitBoundaryUnderflowTestcovering single-bit and boundary-crossing BIT ranges on byte0x80.BitmapBitCountLongBitOffsetParsingTest: its previous expectation of8was an artifact of the underflow. Under Garnet''s modulo-wrapping negative-offset semantics the clamped start wraps to bit index 1, so bits 1..7 of0xFF=7.