Skip to content

fix: reject bare "(" and empty string as score in ZRANGEBYSCORE#3493

Open
Yanhu007 wants to merge 1 commit intovalkey-io:unstablefrom
Yanhu007:fix/zrangebyscore-bare-paren
Open

fix: reject bare "(" and empty string as score in ZRANGEBYSCORE#3493
Yanhu007 wants to merge 1 commit intovalkey-io:unstablefrom
Yanhu007:fix/zrangebyscore-bare-paren

Conversation

@Yanhu007
Copy link
Copy Markdown

Fixes #3483

Problem

ZRANGEBYSCORE (and ZCOUNT, ZRANGESTORE, etc.) accepts a bare ( as a valid score, silently parsing it as (0.0 (exclusive zero). An empty string "" is also accepted as 0.0.

Root cause: when s = "(" (length 1), valkey_strtod_n(s + 1, 0, &eptr) is called with zero length. The parser returns 0.0 and sets eptr to the null terminator. The eptr[0] != 0 check passes.

This was flagged as Coverity CID 901320 (Out-of-bounds access, High impact).

Fix

Add length guards in zslParseRange():

  • len < 2 after detecting ( prefix → C_ERR (bare paren, no number)
  • len == 0 for non-prefixed strings → C_ERR (empty string)

Applied to both min and max parsing paths.

Before / After

# Before
127.0.0.1:6379> ZRANGEBYSCORE zs ( +inf
1) "pos1"
2) "pos2"

# After
127.0.0.1:6379> ZRANGEBYSCORE zs ( +inf
(error) ERR min or max is not a float

When ZRANGEBYSCORE receives a bare "(" (length 1), the parser calls
valkey_strtod_n with zero length, which returns 0.0 and sets eptr
to the null terminator. The existing check passes, so "(" is
silently treated as "(0.0" (exclusive zero).

Similarly, an empty string "" is accepted and parsed as 0.0.

Add length checks:
- Bare "(" (len < 2): return C_ERR immediately
- Empty string (len == 0): return C_ERR immediately

Both min and max parsing paths are fixed.

This was flagged as Coverity CID 901320 (Out-of-bounds access).

Fixes valkey-io#3483
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.79%. Comparing base (c0289c6) to head (99c6173).
⚠️ Report is 1 commits behind head on unstable.

Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #3493      +/-   ##
============================================
+ Coverage     76.53%   76.79%   +0.25%     
============================================
  Files           157      157              
  Lines         79045    79052       +7     
============================================
+ Hits          60501    60709     +208     
+ Misses        18544    18343     -201     
Files with missing lines Coverage Δ
src/t_zset.c 97.03% <100.00%> (+0.09%) ⬆️

... and 16 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] ZRANGEBYSCORE accepts bare "(" as valid score, silently treating it as exclusive 0.0

1 participant