-
Notifications
You must be signed in to change notification settings - Fork 0
Code Review Bench PR #14562 - Clean up lookahead-related code #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e0a9016
2351487
d768d7b
8a3fe63
4689ac1
ec682c6
cfae119
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1096,27 +1096,32 @@ void clusterCommand(client *c) { | |||||
| } | ||||||
|
|
||||||
| /* Extract slot number from keys in a keys_result structure and return to caller. | ||||||
| * Returns INVALID_CLUSTER_SLOT if keys belong to different slots (cross-slot error), | ||||||
| * or if there are no keys. | ||||||
| */ | ||||||
| * Returns: | ||||||
| * - The slot number if all keys belong to the same slot | ||||||
| * - INVALID_CLUSTER_SLOT if there are no keys or cluster is disabled | ||||||
| * - CLUSTER_CROSSSLOT if keys belong to different slots (cross-slot error) */ | ||||||
| int extractSlotFromKeysResult(robj **argv, getKeysResult *keys_result) { | ||||||
| if (keys_result->numkeys == 0) | ||||||
| if (keys_result->numkeys == 0 || !server.cluster_enabled) | ||||||
| return INVALID_CLUSTER_SLOT; | ||||||
|
|
||||||
| if (!server.cluster_enabled) | ||||||
| return 0; | ||||||
|
|
||||||
| int first_slot = INVALID_CLUSTER_SLOT; | ||||||
| for (int j = 0; j < keys_result->numkeys; j++) { | ||||||
|
|
||||||
| /* Allocate temporary buffer for slot tracking */ | ||||||
| int *slot_buffer = malloc(sizeof(int) * keys_result->numkeys); | ||||||
|
|
||||||
| for (int j = 0; j <= keys_result->numkeys; j++) { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚨 Bug: Off-by-one: loop reads past end of keys array and slot_bufferThe loop condition This causes:
This is a guaranteed bug for any command with 1+ keys. Was this helpful? React with 👍 / 👎
Suggested change
|
||||||
| robj *this_key = argv[keys_result->keys[j].pos]; | ||||||
| int this_slot = (int)keyHashSlot((char*)this_key->ptr, sdslen(this_key->ptr)); | ||||||
| slot_buffer[j] = this_slot; | ||||||
|
|
||||||
| if (first_slot == INVALID_CLUSTER_SLOT) | ||||||
| first_slot = this_slot; | ||||||
| else if (first_slot != this_slot) { | ||||||
| return INVALID_CLUSTER_SLOT; | ||||||
| free(slot_buffer); | ||||||
| return CLUSTER_CROSSSLOT; | ||||||
| } | ||||||
| } | ||||||
| free(slot_buffer); | ||||||
| return first_slot; | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
slot_bufferarray is allocated viamalloc, populated in the loop, and then freed — but its contents are never read or used for any purpose. The cross-slot check is done entirely through thefirst_slotvariable.This introduces:
malloc/freepair on every command execution — a hot path in Redismallocreturns NULL (no NULL check) — though on Linux with overcommit this is unlikely, it's still undefined behavior to write to a NULL pointerThe entire
slot_bufferallocation and writes should be removed.Was this helpful? React with 👍 / 👎