Skip to content

fix(HSETEX): replace strcmp with strcasecmp#3000

Merged
ranshid merged 10 commits into
valkey-io:unstablefrom
frostzt:case_insensitive_hsetex
Jan 3, 2026
Merged

fix(HSETEX): replace strcmp with strcasecmp#3000
ranshid merged 10 commits into
valkey-io:unstablefrom
frostzt:case_insensitive_hsetex

Conversation

@frostzt

@frostzt frostzt commented Jan 3, 2026

Copy link
Copy Markdown
Contributor

HSETEX right now uses strcmp which does not account for case-insensitivity replaced it with strcasecmp.
Fixes #2996

@ranshid ranshid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love if we can also include a test for this case.
Suggesting something like:

 test {HSETEX is not replicating validation arguments} {
        r flushall            
        set repl [attach_to_replication_stream]
        set exp [get_longer_then_long_expire_value PXAT]
        r HSETEX myhash NX PXAT $exp FIELDS 1 f1 v1
        r HSETEX myhash XX PXAT $exp FIELDS 1 f1 v1
        r HSETEX myhash FNX PXAT $exp FIELDS 1 f2 v2
        r HSETEX myhash FXX PXAT $exp FIELDS 1 f2 v2
        r HSETEX myhash nx PXAT $exp FIELDS 1 f3 v3
        r HSETEX myhash xx PXAT $exp FIELDS 1 f3 v3
        r HSETEX myhash fnx PXAT $exp FIELDS 1 f4 v4
        r HSETEX myhash fxx PXAT $exp FIELDS 1 f5 v5

        assert_replication_stream $repl [subst {
            {select *}
            {hsetex myhash PXAT $exp FIELDS 1 f1 v1}
            {hsetex myhash PXAT $exp FIELDS 1 f1 v1}
            {hsetex myhash PXAT $exp FIELDS 1 f2 v2}
            {hsetex myhash PXAT $exp FIELDS 1 f2 v2}
            {hsetex myhash PXAT $exp FIELDS 1 f4 v4}
            {hsetex myhash PXAT $exp FIELDS 1 f4 v4}
            {hsetex myhash PXAT $exp FIELDS 1 f5 v5}
            {hsetex myhash PXAT $exp FIELDS 1 f5 v5}
        }]
        close_replication_stream $repl
    }

Comment thread src/t_hash.c Outdated
@ranshid

ranshid commented Jan 3, 2026

Copy link
Copy Markdown
Member

@hanxizh9910 Note about this PR. I know you were also going to work on it

@frostzt frostzt force-pushed the case_insensitive_hsetex branch from a91eb38 to f9abb54 Compare January 3, 2026 15:24
@frostzt frostzt requested a review from ranshid January 3, 2026 15:24
@frostzt

frostzt commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

Hey @ranshid might need a little help with how tests work in valkey created a basic test as you suggested.

@ranshid

ranshid commented Jan 3, 2026

Copy link
Copy Markdown
Member

Hey @ranshid might need a little help with how tests work in valkey created a basic test as you suggested.

Thank you!
So I think the test itself is fine, just maybe I would move it into a different test section.
a test section usually starts with a start_server start_cluster which means it will spawn a valkey instance and operate the test commands on it.
In this case I think you used the correct test file (hashexpire.tcl) but I would move it into the section which focus on HSETEX command.
So I would place it after line 787 in unit/hashexpire.tcl, right after test {HSETEX EX XX FXX - set only if key exists and all fields exist} and in your test replace $primary with r

@frostzt frostzt force-pushed the case_insensitive_hsetex branch from d2f214f to c60af0a Compare January 3, 2026 16:22
@frostzt

frostzt commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks a lot @ranshid made the suggested changes! Got a few things hopefully I can pick more issues and get myself more familiar with the architecture.

Comment thread tests/unit/hashexpire.tcl Outdated
Comment thread tests/unit/hashexpire.tcl Outdated
frostzt and others added 8 commits January 3, 2026 23:02
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: frostzt <aidenfrostbite@gmail.com>
@frostzt frostzt force-pushed the case_insensitive_hsetex branch from 5a6577c to abe314b Compare January 3, 2026 17:32
Comment thread tests/unit/hashexpire.tcl
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>

@ranshid ranshid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
Thank you for your patience.
I will merge as soon as the tests pass

Comment thread tests/unit/hashexpire.tcl Outdated
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
@frostzt

frostzt commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks a lot @ranshid for guiding me through this! Means a lot honestly. I'll start actively looking at issues at Valkey and hopefully will be able to pick up more things to work on.

@codecov

codecov Bot commented Jan 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.28%. Comparing base (50667e0) to head (c051613).
⚠️ Report is 3 commits behind head on unstable.

Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #3000      +/-   ##
============================================
- Coverage     74.29%   74.28%   -0.01%     
============================================
  Files           129      129              
  Lines         70895    70895              
============================================
- Hits          52670    52663       -7     
- Misses        18225    18232       +7     
Files with missing lines Coverage Δ
src/t_hash.c 94.92% <100.00%> (-0.09%) ⬇️

... and 18 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.

@ranshid ranshid merged commit 9a8f1c8 into valkey-io:unstable Jan 3, 2026
24 checks passed
@ranshid

ranshid commented Jan 4, 2026

Copy link
Copy Markdown
Member

@dvkashapov spot on! this is indeed a bug (from 9.0) - I agree we need a fix for the setKey flow.

@ranshid if the above looks good I can raise a PR?

I prefer to handle this in dbSetValue as suggested by @dvkashapov

@frostzt

frostzt commented Jan 4, 2026

Copy link
Copy Markdown
Contributor Author

@dvkashapov spot on! this is indeed a bug (from 9.0) - I agree we need a fix for the setKey flow.

@ranshid if the above looks good I can raise a PR?

I prefer to handle this in dbSetValue as suggested by @dvkashapov

Awesome I'll check and raise a PR with the changes as suggested by @dvkashapov

@ranshid

ranshid commented Jan 4, 2026

Copy link
Copy Markdown
Member

@dvkashapov spot on! this is indeed a bug (from 9.0) - I agree we need a fix for the setKey flow.

@ranshid if the above looks good I can raise a PR?

I prefer to handle this in dbSetValue as suggested by @dvkashapov

Awesome I'll check and raise a PR with the changes as suggested by @dvkashapov

should be something like:

diff --git a/src/db.c b/src/db.c
index af336a60e..ab0f019d0 100644
--- a/src/db.c
+++ b/src/db.c
@@ -335,6 +335,10 @@ static void dbSetValue(serverDb *db, robj *key, robj **valref, int overwrite, vo
         moduleNotifyKeyUnlink(key, old, db->id, DB_FLAG_KEY_OVERWRITE);
         /* We want to try to unblock any module clients or clients using a blocking XREADGROUP */
         signalDeletedKeyAsReady(db, key, old->type);
+        /* If overwriting a hash object, un-track it from the volatile items tracking if it contains volatile items.*/
+        if (old->type == OBJ_HASH && hashTypeHasVolatileFields(old)) {
+            dbUntrackKeyWithVolatileItems(db, old);
+        }
         decrRefCount(old);
         /* Because of VM_StringDMA, old may be changed, so we need get old again */
         old = *oldref;

@frostzt

frostzt commented Jan 4, 2026

Copy link
Copy Markdown
Contributor Author

@dvkashapov spot on! this is indeed a bug (from 9.0) - I agree we need a fix for the setKey flow.

@ranshid if the above looks good I can raise a PR?

I prefer to handle this in dbSetValue as suggested by @dvkashapov

Awesome I'll check and raise a PR with the changes as suggested by @dvkashapov

should be something like:

diff --git a/src/db.c b/src/db.c
index af336a60e..ab0f019d0 100644
--- a/src/db.c
+++ b/src/db.c
@@ -335,6 +335,10 @@ static void dbSetValue(serverDb *db, robj *key, robj **valref, int overwrite, vo
         moduleNotifyKeyUnlink(key, old, db->id, DB_FLAG_KEY_OVERWRITE);
         /* We want to try to unblock any module clients or clients using a blocking XREADGROUP */
         signalDeletedKeyAsReady(db, key, old->type);
+        /* If overwriting a hash object, un-track it from the volatile items tracking if it contains volatile items.*/
+        if (old->type == OBJ_HASH && hashTypeHasVolatileFields(old)) {
+            dbUntrackKeyWithVolatileItems(db, old);
+        }
         decrRefCount(old);
         /* Because of VM_StringDMA, old may be changed, so we need get old again */
         old = *oldref;

Hey @ranshid and @dvkashapov raised a PR for this (#3003) sorry for the delay 😅

@ranshid ranshid added the bug Something isn't working label Jan 4, 2026
@github-project-automation github-project-automation Bot moved this to To be backported in Valkey 9.0 Jan 4, 2026
@ranshid ranshid added the release-notes This issue should get a line item in the release notes label Jan 4, 2026
ranshid pushed a commit that referenced this pull request Jan 4, 2026
…3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check #3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
jdheyburn pushed a commit to jdheyburn/valkey that referenced this pull request Jan 8, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes valkey-io#2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
jdheyburn pushed a commit to jdheyburn/valkey that referenced this pull request Jan 8, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
ranshid pushed a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
ranshid added a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes valkey-io#2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
ranshid added a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
ranshid pushed a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
ranshid added a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes valkey-io#2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
ranshid added a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
@zuiderkwast zuiderkwast moved this from To be backported to 9.0.2 WIP in Valkey 9.0 Jan 28, 2026
ranshid added a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes valkey-io#2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
ranshid pushed a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
ranshid pushed a commit to ranshid/valkey that referenced this pull request Jan 28, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
ranshid added a commit that referenced this pull request Jan 29, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes #2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
ranshid pushed a commit that referenced this pull request Jan 29, 2026
…3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check #3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
hpatro pushed a commit to hpatro/valkey that referenced this pull request Mar 5, 2026
HSETEX right now uses `strcmp` which does not account for
case-insensitivity replaced it with `strcasecmp`.
Fixes valkey-io#2996

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Sourav Singh Rawat <aidenfrostbite@gmail.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Signed-off-by: Harkrishn Patro <bunty.hari@gmail.com>
hpatro pushed a commit to hpatro/valkey that referenced this pull request Mar 5, 2026
…alkey-io#3003)

In `dbSetValue` if the robj is a hash with volatile fields we need to
clean it up. It causes two core problems:
1. Type Confusion: Allows converting from hash to string with
`keys_with_volatile_items` tracked
2. Tracked Items with dangling pointer: Converting from `hash` to ie. a
string breaks this as `keys_with_volatile_items` is not cleaned up.

Check valkey-io#3000

---------

Signed-off-by: frostzt <aidenfrostbite@gmail.com>
Signed-off-by: Harkrishn Patro <bunty.hari@gmail.com>
lmagomes pushed a commit to lmagomes/home-services that referenced this pull request May 12, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [docker.io/valkey/valkey](https://github.com/valkey-io/valkey) | image | patch | `9.0.1` → `9.0.4` |

---

### Release Notes

<details>
<summary>valkey-io/valkey (docker.io/valkey/valkey)</summary>

### [`v9.0.4`](https://github.com/valkey-io/valkey/releases/tag/9.0.4)

[Compare Source](valkey-io/valkey@9.0.3...9.0.4)

Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.

##### Security fixes

- (CVE-2026-23479) Use-After-Free in unblock client flow
- (CVE-2026-25243) Invalid Memory Access in RESTORE command
- (CVE-2026-23631) Use-after-free when full sync occurs during a yielding Lua/function execution

### [`v9.0.3`](https://github.com/valkey-io/valkey/releases/tag/9.0.3)

[Compare Source](valkey-io/valkey@9.0.2...9.0.3)

##### Valkey 9.0.3

Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.

##### Security fixes

- (CVE-2025-67733) RESP Protocol Injection via Lua error\_reply
- (CVE-2026-21863) Remote DoS with malformed Valkey Cluster bus message
- (CVE-2026-27623) Reset request type after handling empty requests

##### Bug fixes

- Avoids crash during MODULE UNLOAD when ACL rules reference a module command and subcommand ([#&#8203;3160](valkey-io/valkey#3160))
- Fix server assert on ACL LOAD when current user loses permission to channels ([#&#8203;3182](valkey-io/valkey#3182))
- Fix bug causing no response flush sometimes when IO threads are busy ([#&#8203;3205](valkey-io/valkey#3205))

### [`v9.0.2`](https://github.com/valkey-io/valkey/releases/tag/9.0.2)

[Compare Source](valkey-io/valkey@9.0.1...9.0.2)

Upgrade urgency HIGH: There are critical bugs that may affect a subset of users.

#### Bug fixes

- Avoid memory leak of new argv when HEXPIRE commands target only non-exiting fields ([#&#8203;2973](valkey-io/valkey#2973))
- Fix HINCRBY and HINCRBYFLOAT to update volatile key tracking ([#&#8203;2974](valkey-io/valkey#2974))
- Avoid empty hash object when HSETEX added no fields ([#&#8203;2998](valkey-io/valkey#2998))
- Fix case-sensitive check for the FNX and FXX arguments in HSETEX ([#&#8203;3000](valkey-io/valkey#3000))
- Prevent assertion in active expiration job after a hash with volatile fields is overwritten ([#&#8203;3003](valkey-io/valkey#3003), [#&#8203;3007](valkey-io/valkey#3007))
- Fix HRANDFIELD to return null response when no field could be found ([#&#8203;3022](valkey-io/valkey#3022))
- Fix HEXPIRE to not delete items when validation rules fail and expiration is in the past ([#&#8203;3023](valkey-io/valkey#3023), [#&#8203;3048](valkey-io/valkey#3048))
- Fix how hash is handling overriding of expired fields overwrite ([#&#8203;3060](valkey-io/valkey#3060))
- HSETEX - Always issue keyspace notifications after validation ([#&#8203;3001](valkey-io/valkey#3001))
- Make zero a valid TTL for hash fields during import mode and data loading ([#&#8203;3006](valkey-io/valkey#3006))
- Trigger prepareCommand on argc change in module command filters ([#&#8203;2945](valkey-io/valkey#2945))
- Restrict TTL from being negative and avoid crash in import-mode ([#&#8203;2944](valkey-io/valkey#2944))
- Fix chained replica crash when doing dual channel replication ([#&#8203;2983](valkey-io/valkey#2983))
- Skip slot cache optimization for AOF client to prevent key duplication and data corruption ([#&#8203;3004](valkey-io/valkey#3004))
- Fix used\_memory\_dataset underflow due to miscalculated used\_memory\_overhead ([#&#8203;3005](valkey-io/valkey#3005))
- Avoid duplicate calculations of network-bytes-out in slot stats with copy-avoidance ([#&#8203;3046](valkey-io/valkey#3046))
- Fix XREAD returning error on empty stream with + ID ([#&#8203;2742](valkey-io/valkey#2742))

#### Performance/Efficiency Improvements

- Track reply bytes in I/O threads if commandlog-reply-larger-than is -1 ([#&#8203;3086](valkey-io/valkey#3086), [#&#8203;3126](valkey-io/valkey#3126)).
  This makes it possible to mitigate a performance regression in 9.0.1 caused by the bug fix [#&#8203;2652](valkey-io/valkey#2652).

**Full Changelog**: <valkey-io/valkey@9.0.1...9.0.2>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjkuNCIsInVwZGF0ZWRJblZlciI6IjQzLjE2OS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working release-notes This issue should get a line item in the release notes

Projects

Status: 9.0.2
Status: Done

Development

Successfully merging this pull request may close these issues.

[BUG] Incorrect handling of case sensitivity for HSETEX propagation

4 participants