Skip to content

Clean up lookahead-related code#16

Open
tomerqodo wants to merge 7 commits intocoderabbit_combined_20260121_augment_sentry_coderabbit_1_base_clean_up_lookahead-related_code_pr94from
coderabbit_combined_20260121_augment_sentry_coderabbit_1_head_clean_up_lookahead-related_code_pr94
Open

Clean up lookahead-related code#16
tomerqodo wants to merge 7 commits intocoderabbit_combined_20260121_augment_sentry_coderabbit_1_base_clean_up_lookahead-related_code_pr94from
coderabbit_combined_20260121_augment_sentry_coderabbit_1_head_clean_up_lookahead-related_code_pr94

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 22, 2026

Benchmark PR from qodo-benchmark#94

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection and error handling for cluster commands spanning multiple slots
    • Enhanced slot validity tracking in cluster operations
    • Refined error reporting for cross-slot scenarios

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 22, 2026

Walkthrough

This pull request refactors cluster slot detection mechanisms by introducing a new CLUSTER_CROSSSLOT constant and consolidating slot sentinel values. The extractSlotFromKeysResult function is enhanced to detect cross-slot conditions via buffer-based slot tracking. Existing GETSLOT_NOKEYS and GETSLOT_CROSSSLOT macros are replaced with INVALID_CLUSTER_SLOT and CLUSTER_CROSSSLOT across all related call sites.

Changes

Cohort / File(s) Summary
Cluster Constants Definition
src/cluster.h
Added CLUSTER_CROSSSLOT macro (-2) alongside existing cluster status macros.
Core Slot Extraction Logic
src/cluster.c
Enhanced extractSlotFromKeysResult with temporary slot-tracking buffer to detect when keys map to different slots; returns CLUSTER_CROSSSLOT on mismatch, INVALID_CLUSTER_SLOT for empty/disabled cases.
Cluster ASM Integration
src/cluster_asm.c
Updated asmFeedMigrationClient, asmModulePropagateBeforeSlotSnapshot, and related functions to use INVALID_CLUSTER_SLOT and CLUSTER_CROSSSLOT in place of old GETSLOT_* sentinels.
Slot Statistics
src/cluster_slot_stats.c
Replaced -1 checks in canAddNetworkBytesOut, canAddCpuDuration, and canAddNetworkBytesIn with INVALID_CLUSTER_SLOT comparisons.
Command Slot Determination
src/db.c
Refactored getSlotFromCommand and extractKeysAndSlot to use new constants and delegate slot extraction to extractSlotFromKeysResult.
Cross-slot Error Handling
src/server.c
Added handling for CLUSTER_CROSSSLOT in preprocessCommand to set CLIENT_READ_CROSS_SLOT error and reset slot to INVALID_CLUSTER_SLOT.
Constant Migration
src/server.h
Removed deprecated GETSLOT_NOKEYS and GETSLOT_CROSSSLOT macros from public header.
Documentation
src/networking.c
Clarified comment in freePendingCommand regarding NULL argv element handling.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


🐰 Through slots we hop with whiskers held high,
Cross-slot checks dance, no keys pass by,
New sentinels bloom where old ones did rest,
Our cluster detection is clever and blessed! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Clean up lookahead-related code' is vague and does not clearly match the actual changes, which focus on refactoring cluster slot handling constants and improving slot extraction logic. Consider revising the title to more accurately reflect the main changes, such as 'Refactor cluster slot constants and extraction logic' or 'Consolidate cluster slot handling with new sentinel values'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/cluster.c`:
- Around line 1098-1125: The function extractSlotFromKeysResult contains an
off‑by‑one loop (it uses j <= keys_result->numkeys) and allocates an unused
slot_buffer via malloc/free; remove the allocation and all uses of slot_buffer,
change the loop to for (int j = 0; j < keys_result->numkeys; j++), compute
this_slot with keyHashSlot using argv[keys_result->keys[j].pos], compare to
first_slot as currently done, return CLUSTER_CROSSSLOT on mismatch, and return
first_slot at the end — this eliminates the out‑of‑bounds access and the
deprecated malloc/free usage.

In `@src/db.c`:
- Around line 437-438: The loop in extractSlotFromKeysResult is off-by-one and
reads/writes past the allocated slot_buffer and keys_result->keys; change the
loop condition from using <= keys_result->numkeys to < keys_result->numkeys so
the loop iterates indices 0..numkeys-1 (ensuring accesses to
keys_result->keys[j] and slot_buffer[j] stay in-bounds), then run tests to
confirm no more OOB accesses involving slot_buffer, keys_result, or numkeys.
🧹 Nitpick comments (1)
src/db.c (1)

3200-3205: Consider initializing *slot when num_keys <= 0 for defensive safety.

When num_keys is 0 or -1 (error case), *slot is never assigned, leaving it with whatever value the caller passed in (potentially uninitialized or stale). While callers should check num_keys before using *slot, setting it to INVALID_CLUSTER_SLOT in the else branch would be safer:

♻️ Proposed fix
     if (num_keys > 0) {
         *slot = extractSlotFromKeysResult(argv, result);
+    } else {
+        *slot = INVALID_CLUSTER_SLOT;
     }
     return num_keys;
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb9e7e and 7b01b6d.

📒 Files selected for processing (8)
  • src/cluster.c
  • src/cluster.h
  • src/cluster_asm.c
  • src/cluster_slot_stats.c
  • src/db.c
  • src/networking.c
  • src/server.c
  • src/server.h
🧰 Additional context used
🧬 Code graph analysis (3)
src/cluster_slot_stats.c (1)
src/server.h (1)
  • clusterSlotStatsEnabled (3741-3741)
src/cluster.c (1)
src/cluster.h (1)
  • keyHashSlot (66-85)
src/db.c (1)
src/cluster.c (1)
  • extractSlotFromKeysResult (1103-1126)
🪛 GitHub Actions: CI
src/server.h

[error] 4308-4309: Deprecated declarations: 'free' and 'malloc' are marked deprecated in this header.

src/cluster.c

[error] 1110-1124: cluster.c: 'malloc' and 'free' are deprecated. The build enables -Werror, causing these deprecated-declarations to fail compilation.

🪛 GitHub Actions: Codecov
src/cluster.c

[error] 1110-1124: Compilation failed due to deprecated memory management functions: malloc and free are deprecated under -Werror. The build flags promote deprecated-declarations as errors. Adjust code to use appropriate allocation patterns or remove the deprecation (e.g., use realloc or project-specific allocators) to fix the cluster.o compilation errors.

🪛 GitHub Actions: External Server Tests
src/cluster.c

[error] 1110-1124: Werror: deprecated usage of malloc/free detected. Replacement with calloc/realloc or updated memory management required. References to malloc at 1110 and free at 1120/1124 trigger failures.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-old-chain-jemalloc
  • GitHub Check: Analyze (cpp)
🔇 Additional comments (8)
src/networking.c (1)

5099-5099: Good documentation improvement.

The added comment clarifies a non-obvious case where argv[j] can be NULL due to the partial cleanup performed in reclaimPendingCommand when handling IO thread commands. This improves code maintainability by documenting the cross-function dependency.

src/cluster.h (1)

26-26: Macro addition looks good.

Clear sentinel definition alongside INVALID_CLUSTER_SLOT is consistent with the refactor.

src/server.h (1)

2412-2412: Comment tweak is fine.

No functional changes here.

src/cluster_slot_stats.c (1)

139-141: No issue found. The guard functions are correct as written.

c->slot != INVALID_CLUSTER_SLOT properly excludes both INVALID_CLUSTER_SLOT (-1) and CLUSTER_CROSSSLOT (-2). When a command has cross-slot keys, extractSlotFromKeysResult() returns CLUSTER_CROSSSLOT, but preprocessCommand() (server.c:4143-4145) converts it to INVALID_CLUSTER_SLOT before c->slot is assigned. By the time slot-stats aggregation functions execute, c->slot can only be a valid slot (≥ 0) or INVALID_CLUSTER_SLOT (-1), making the serverAssert(c->slot >= 0) checks safe.

Likely an incorrect or invalid review comment.

src/server.c (1)

4135-4147: No action needed. The code is safe as-is.

The contract of extractKeysAndSlot() (defined in src/db.c:3185–3207) only modifies the slot when num_keys > 0. For zero-key commands, it returns num_keys == 0 without touching the slot parameter. Since pcmd->slot is initialized to INVALID_CLUSTER_SLOT at line 4109, the condition pcmd->slot == CLUSTER_CROSSSLOT at line 4143 will never be true for zero-key commands, preventing false positives.

Likely an incorrect or invalid review comment.

src/cluster_asm.c (2)

754-778: LGTM: keyless and cross-slot handling aligned with new sentinels.

The INVALID_CLUSTER_SLOT early return and CLUSTER_CROSSSLOT flagging are consistent with the new slot sentinel semantics.


3455-3465: LGTM: module propagation now correctly respects CLUSTER_CROSSSLOT / INVALID_CLUSTER_SLOT.

The updated checks are consistent with the new sentinel values and preserve safety around slot range validation.

src/db.c (1)

428-431: LGTM!

The updated comment clearly documents the return value semantics, and the early return correctly handles the edge cases when no slot can be determined.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 1098 to 1125
/* 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++) {
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;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix off‑by‑one and remove deprecated malloc/free.

Line 1112 iterates with <= keys_result->numkeys, which reads/writes one past the end of keys_result->keys (and slot_buffer). Also, malloc/free are deprecated in this codebase and currently fail CI. The buffer isn’t used, so removing it fixes both issues.

🛠️ Proposed fix
-    int first_slot = INVALID_CLUSTER_SLOT;
-
-    /* Allocate temporary buffer for slot tracking */
-    int *slot_buffer = malloc(sizeof(int) * keys_result->numkeys);
-
-    for (int j = 0; j <= keys_result->numkeys; j++) {
-        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;
+    int first_slot = INVALID_CLUSTER_SLOT;
+
+    for (int j = 0; j < keys_result->numkeys; j++) {
+        robj *this_key = argv[keys_result->keys[j].pos];
+        int this_slot = (int)keyHashSlot((char*)this_key->ptr, sdslen(this_key->ptr));
         if (first_slot == INVALID_CLUSTER_SLOT)
             first_slot = this_slot;
         else if (first_slot != this_slot) {
-            free(slot_buffer);
             return CLUSTER_CROSSSLOT;
         }
     }
-    free(slot_buffer);
     return first_slot;
🧰 Tools
🪛 GitHub Actions: CI

[error] 1110-1124: cluster.c: 'malloc' and 'free' are deprecated. The build enables -Werror, causing these deprecated-declarations to fail compilation.

🪛 GitHub Actions: Codecov

[error] 1110-1124: Compilation failed due to deprecated memory management functions: malloc and free are deprecated under -Werror. The build flags promote deprecated-declarations as errors. Adjust code to use appropriate allocation patterns or remove the deprecation (e.g., use realloc or project-specific allocators) to fix the cluster.o compilation errors.

🪛 GitHub Actions: External Server Tests

[error] 1110-1124: Werror: deprecated usage of malloc/free detected. Replacement with calloc/realloc or updated memory management required. References to malloc at 1110 and free at 1120/1124 trigger failures.

🤖 Prompt for AI Agents
In `@src/cluster.c` around lines 1098 - 1125, The function
extractSlotFromKeysResult contains an off‑by‑one loop (it uses j <=
keys_result->numkeys) and allocates an unused slot_buffer via malloc/free;
remove the allocation and all uses of slot_buffer, change the loop to for (int j
= 0; j < keys_result->numkeys; j++), compute this_slot with keyHashSlot using
argv[keys_result->keys[j].pos], compare to first_slot as currently done, return
CLUSTER_CROSSSLOT on mismatch, and return first_slot at the end — this
eliminates the out‑of‑bounds access and the deprecated malloc/free usage.

Comment on lines +437 to +438
/* Extract slot from the keys result. */
int slot = extractSlotFromKeysResult(argv, &result);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n -A 30 'int extractSlotFromKeysResult' src/cluster.c

Repository: qodo-benchmark/redis-combined-coderabbit

Length of output: 1398


Critical: Off-by-one error in extractSlotFromKeysResult causes heap buffer overflow.

The extractSlotFromKeysResult function (defined in src/cluster.c, line 1103) has a critical buffer overflow bug. The function allocates slot_buffer with space for numkeys elements (line 1110), but the loop condition on line 1112 uses j <= keys_result->numkeys instead of j < keys_result->numkeys, causing:

  1. Out-of-bounds read from keys_result->keys[numkeys] (line 1113)
  2. Out-of-bounds write to slot_buffer[numkeys] (line 1115)

Both occur when the loop accesses index numkeys on an array allocated for indices 0 to numkeys-1. Fix by changing the loop condition to j < keys_result->numkeys.

🤖 Prompt for AI Agents
In `@src/db.c` around lines 437 - 438, The loop in extractSlotFromKeysResult is
off-by-one and reads/writes past the allocated slot_buffer and
keys_result->keys; change the loop condition from using <= keys_result->numkeys
to < keys_result->numkeys so the loop iterates indices 0..numkeys-1 (ensuring
accesses to keys_result->keys[j] and slot_buffer[j] stay in-bounds), then run
tests to confirm no more OOB accesses involving slot_buffer, keys_result, or
numkeys.

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.

2 participants