Fix non-positive count on LMPOP and LPOP/RPOP - #2010
Open
hexonal wants to merge 1 commit into
Open
Conversation
Two symptoms of the same gap: a count of 0 reaches the list pop path
without being handled.
LMPOP with COUNT 0 or a negative COUNT throws NullReferenceException out
of ProcessMessages and terminates the RESP session:
RPUSH L a b c
LMPOP 1 L LEFT COUNT 0 -> connection closed, no reply
The count is parsed at ListCommands.cs without a lower bound and flows
into the storage layer. BLMPOP already rejects the same input with
"ERR count should be greater than 0", so add the same check to LMPOP.
It reuses the error path and message already present a few lines below,
which matches what Redis returns for this case.
LPOP/RPOP with an explicit count of 0 write no reply at all. In ListPop
neither the empty-list branch nor the count > 1 branch fires, so the
command emits zero bytes. Interactively the client just waits; in a
pipeline every following reply shifts by one and is silently attributed
to the wrong command:
LPOP P 0 / ECHO marker1 / ECHO marker2
before: $7 marker1 | $7 marker2 (two replies for three commands)
after: *0 | $7 marker1 | $7 marker2
Redis replies with an empty array here (t_list.c, "fast exit path"), so
write one. Single-element pops still reply with a bare bulk string and
the count > 1 path is untouched.
Verified on macOS arm64, net10.0 Release: both new assertions fail
without the change -- LMPOP with RedisServerException missing, LPOP
after a 30s timeout -- and pass with it. RespListTests: 104/104.
dotnet format clean. net8.0 builds clean; its tests were not run here,
no net8.0 runtime in this environment.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes two RESP list-pop edge cases where a COUNT of 0 (or non-positive for LMPOP) previously reached unhandled paths, causing either a session drop (LMPOP COUNT 0) or a missing reply (LPOP/RPOP key 0), and adds regression tests to lock in Redis-compatible behavior.
Changes:
- Reject
LMPOP ... COUNT < 1at the RESP parsing layer with the existing Redis-compatible error message. - Ensure
LPOP/RPOPwith an explicitcount == 0returns an empty array reply instead of producing no reply. - Extend/add tests covering both scenarios, including verifying the connection remains usable and subsequent pipelined replies are not mis-paired.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/standalone/Garnet.test.collections/RespListTests.cs | Adds/extends regression tests for LMPOP COUNT 0/-1 and LPOP/RPOP count 0 reply semantics and connection/pipeline safety. |
| libs/server/Resp/Objects/ListCommands.cs | Validates LMPOP COUNT is >= 1 and returns the established “count should be greater than 0” error. |
| libs/server/Objects/List/ListObjectImpl.cs | Writes an explicit empty-array RESP reply when LPOP/RPOP is invoked with count <= 0, preventing zero-byte responses. |
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.
Two symptoms of the same gap — a count of 0 reaching the list pop path unhandled.
LMPOP with a non-positive COUNT kills the session
NullReferenceExceptionout ofProcessMessages. The count is read atListCommands.cswith no lower bound and flows into the storage layer.BLMPOPalready rejects the same input correctly — I checked against a live server:So
LMPOPis the odd one out. The fix adds the same bound to the existing condition; the error path and message a few lines below were already there and already match what Redis returns for this case, so nothing new is introduced.LPOP/RPOP with an explicit count of 0 send no reply
In
ListPop, for a non-empty list withcount == 0, neither the empty-list branch nor thecount > 1branch fires, so the command writes zero bytes.Interactively the client just hangs. In a pipeline it is worse — every following reply shifts by one and is silently attributed to the wrong command:
Redis replies with an empty array here (
t_list.c, thehascount && !countfast-exit path), so write one.Scope
Single-element pops still reply with a bare bulk string, and the
count > 1path is untouched — spot-checked against a live server:Testing
CanDoRejectBadLMPOPCommandextended withCOUNT 0andCOUNT -1, asserting the error, that the connection survives, and that the list is untouched.LPOPAndRPOPWithZeroCountReturnEmptyArray, which also asserts a followingECHOis not mis-paired.RespListTests: 104/104.dotnet format --verify-no-changesclean on all three files.net8.0builds clean but its tests were not run here — no net8.0 runtime in this environment.