Skip to content

Commit ec58a48

Browse files
sungming2Seungmin Lee
andauthored
Add helper function for padded pointer copy (valkey-io#2388)
## Closes valkey-io#2383 Refactor the logic for writing a fixed length (8 byte) pointer field with zero padding on 32‑bit targets by: * Introducing a new helper function writePointerWithPadding * Refactoring encodeFailureReportKey() and encodeTimeoutKey() to use this helper instead of in‑lining the padding logic Signed-off-by: Seungmin Lee <sungming@amazon.com> Co-authored-by: Seungmin Lee <sungming@amazon.com>
1 parent ee5b72b commit ec58a48

File tree

6 files changed

+49
-15
lines changed

6 files changed

+49
-15
lines changed

src/cluster_legacy.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,8 +1692,6 @@ clusterNode *createClusterNode(char *nodename, int flags) {
16921692
* timestamps and keep the radix‐tree keys compact. The resulting timestamp is stored
16931693
* in big‑endian format, followed by the pointer to the clusterNode. */
16941694
static void encodeFailureReportKey(clusterNode *node, mstime_t report_time, unsigned char *buf_out) {
1695-
const size_t node_ptr_pad_bytes = (sizeof(clusterNode *) == 4) ? 4 : 0; // pad on 32-bit
1696-
16971695
/* Round up to the next second for fewer key splits and quorum grace */
16981696
mstime_t bucketed_time = (report_time / SEC_IN_MS) * SEC_IN_MS + SEC_IN_MS;
16991697

@@ -1702,8 +1700,7 @@ static void encodeFailureReportKey(clusterNode *node, mstime_t report_time, unsi
17021700
memcpy(buf_out, &big_endian_time, sizeof(uint64_t));
17031701

17041702
/* Append the node pointer, plus padding if necessary */
1705-
memcpy(buf_out + sizeof(uint64_t), &node, sizeof(node));
1706-
if (node_ptr_pad_bytes) memset(buf_out + sizeof(uint64_t) + sizeof(node), 0, node_ptr_pad_bytes);
1703+
writePointerWithPadding(buf_out + sizeof(uint64_t), node);
17071704
}
17081705

17091706
/* Reverses the operation of encodeFailureReportKey, reading back a timestamp

src/timeout.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,18 @@ int clientsCronHandleTimeout(client *c, mstime_t now_ms) {
8989
#define CLIENT_ST_KEYLEN 16 /* 8 bytes mstime + 8 bytes client ID. */
9090

9191
/* Given client ID and timeout, write the resulting radix tree key in buf. */
92-
void encodeTimeoutKey(unsigned char *buf, uint64_t timeout, client *c) {
92+
void encodeTimeoutKey(client *c, uint64_t timeout, unsigned char *buf_out) {
9393
timeout = htonu64(timeout);
94-
memcpy(buf, &timeout, sizeof(timeout));
95-
memcpy(buf + 8, &c, sizeof(c));
96-
if (sizeof(c) == 4) memset(buf + 12, 0, 4); /* Zero padding for 32bit target. */
94+
memcpy(buf_out, &timeout, sizeof(timeout));
95+
writePointerWithPadding(buf_out + sizeof(timeout), c);
9796
}
9897

9998
/* Given a key encoded with encodeTimeoutKey(), resolve the fields and write
10099
* the timeout into *toptr and the client pointer into *cptr. */
101-
void decodeTimeoutKey(unsigned char *buf, uint64_t *toptr, client **cptr) {
102-
memcpy(toptr, buf, sizeof(*toptr));
103-
*toptr = ntohu64(*toptr);
104-
memcpy(cptr, buf + 8, sizeof(*cptr));
100+
void decodeTimeoutKey(unsigned char *buf, uint64_t *timeout_ptr, client **client_ptr) {
101+
memcpy(timeout_ptr, buf, sizeof(*timeout_ptr));
102+
*timeout_ptr = ntohu64(*timeout_ptr);
103+
memcpy(client_ptr, buf + sizeof(*timeout_ptr), sizeof(*client_ptr));
105104
}
106105

107106
/* Add the specified client id / timeout as a key in the radix tree we use
@@ -111,7 +110,7 @@ void addClientToTimeoutTable(client *c) {
111110
if (c->bstate->timeout == 0) return;
112111
uint64_t timeout = c->bstate->timeout;
113112
unsigned char buf[CLIENT_ST_KEYLEN];
114-
encodeTimeoutKey(buf, timeout, c);
113+
encodeTimeoutKey(c, timeout, buf);
115114
if (raxTryInsert(server.clients_timeout_table, buf, sizeof(buf), NULL, NULL)) c->flag.in_to_table = 1;
116115
}
117116

@@ -122,7 +121,7 @@ void removeClientFromTimeoutTable(client *c) {
122121
c->flag.in_to_table = 0;
123122
uint64_t timeout = c->bstate->timeout;
124123
unsigned char buf[CLIENT_ST_KEYLEN];
125-
encodeTimeoutKey(buf, timeout, c);
124+
encodeTimeoutKey(c, timeout, buf);
126125
raxRemove(server.clients_timeout_table, buf, sizeof(buf), NULL);
127126
}
128127

src/unit/test_files.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ int test_ld2string(int argc, char **argv, int flags);
193193
int test_fixedpoint_d2string(int argc, char **argv, int flags);
194194
int test_version2num(int argc, char **argv, int flags);
195195
int test_reclaimFilePageCache(int argc, char **argv, int flags);
196+
int test_writePointerWithPadding(int argc, char **argv, int flags);
196197
int test_valkey_strtod(int argc, char **argv, int flags);
197198
int test_vector(int argc, char **argv, int flags);
198199
int test_ziplistCreateIntList(int argc, char **argv, int flags);
@@ -251,7 +252,7 @@ unitTest __test_quicklist_c[] = {{"test_quicklistCreateList", test_quicklistCrea
251252
unitTest __test_rax_c[] = {{"test_raxRandomWalk", test_raxRandomWalk}, {"test_raxIteratorUnitTests", test_raxIteratorUnitTests}, {"test_raxTryInsertUnitTests", test_raxTryInsertUnitTests}, {"test_raxRegressionTest1", test_raxRegressionTest1}, {"test_raxRegressionTest2", test_raxRegressionTest2}, {"test_raxRegressionTest3", test_raxRegressionTest3}, {"test_raxRegressionTest4", test_raxRegressionTest4}, {"test_raxRegressionTest5", test_raxRegressionTest5}, {"test_raxRegressionTest6", test_raxRegressionTest6}, {"test_raxBenchmark", test_raxBenchmark}, {"test_raxHugeKey", test_raxHugeKey}, {"test_raxFuzz", test_raxFuzz}, {"test_raxRecompressHugeKey", test_raxRecompressHugeKey}, {NULL, NULL}};
252253
unitTest __test_sds_c[] = {{"test_sds", test_sds}, {"test_typesAndAllocSize", test_typesAndAllocSize}, {"test_sdsHeaderSizes", test_sdsHeaderSizes}, {"test_sdssplitargs", test_sdssplitargs}, {NULL, NULL}};
253254
unitTest __test_sha1_c[] = {{"test_sha1", test_sha1}, {NULL, NULL}};
254-
unitTest __test_util_c[] = {{"test_string2ll", test_string2ll}, {"test_string2l", test_string2l}, {"test_ll2string", test_ll2string}, {"test_ld2string", test_ld2string}, {"test_fixedpoint_d2string", test_fixedpoint_d2string}, {"test_version2num", test_version2num}, {"test_reclaimFilePageCache", test_reclaimFilePageCache}, {NULL, NULL}};
255+
unitTest __test_util_c[] = {{"test_string2ll", test_string2ll}, {"test_string2l", test_string2l}, {"test_ll2string", test_ll2string}, {"test_ld2string", test_ld2string}, {"test_fixedpoint_d2string", test_fixedpoint_d2string}, {"test_version2num", test_version2num}, {"test_reclaimFilePageCache", test_reclaimFilePageCache}, {"test_writePointerWithPadding", test_writePointerWithPadding}, {NULL, NULL}};
255256
unitTest __test_valkey_strtod_c[] = {{"test_valkey_strtod", test_valkey_strtod}, {NULL, NULL}};
256257
unitTest __test_vector_c[] = {{"test_vector", test_vector}, {NULL, NULL}};
257258
unitTest __test_ziplist_c[] = {{"test_ziplistCreateIntList", test_ziplistCreateIntList}, {"test_ziplistPop", test_ziplistPop}, {"test_ziplistGetElementAtIndex3", test_ziplistGetElementAtIndex3}, {"test_ziplistGetElementOutOfRange", test_ziplistGetElementOutOfRange}, {"test_ziplistGetLastElement", test_ziplistGetLastElement}, {"test_ziplistGetFirstElement", test_ziplistGetFirstElement}, {"test_ziplistGetElementOutOfRangeReverse", test_ziplistGetElementOutOfRangeReverse}, {"test_ziplistIterateThroughFullList", test_ziplistIterateThroughFullList}, {"test_ziplistIterateThroughListFrom1ToEnd", test_ziplistIterateThroughListFrom1ToEnd}, {"test_ziplistIterateThroughListFrom2ToEnd", test_ziplistIterateThroughListFrom2ToEnd}, {"test_ziplistIterateThroughStartOutOfRange", test_ziplistIterateThroughStartOutOfRange}, {"test_ziplistIterateBackToFront", test_ziplistIterateBackToFront}, {"test_ziplistIterateBackToFrontDeletingAllItems", test_ziplistIterateBackToFrontDeletingAllItems}, {"test_ziplistDeleteInclusiveRange0To0", test_ziplistDeleteInclusiveRange0To0}, {"test_ziplistDeleteInclusiveRange0To1", test_ziplistDeleteInclusiveRange0To1}, {"test_ziplistDeleteInclusiveRange1To2", test_ziplistDeleteInclusiveRange1To2}, {"test_ziplistDeleteWithStartIndexOutOfRange", test_ziplistDeleteWithStartIndexOutOfRange}, {"test_ziplistDeleteWithNumOverflow", test_ziplistDeleteWithNumOverflow}, {"test_ziplistDeleteFooWhileIterating", test_ziplistDeleteFooWhileIterating}, {"test_ziplistReplaceWithSameSize", test_ziplistReplaceWithSameSize}, {"test_ziplistReplaceWithDifferentSize", test_ziplistReplaceWithDifferentSize}, {"test_ziplistRegressionTestForOver255ByteStrings", test_ziplistRegressionTestForOver255ByteStrings}, {"test_ziplistRegressionTestDeleteNextToLastEntries", test_ziplistRegressionTestDeleteNextToLastEntries}, {"test_ziplistCreateLongListAndCheckIndices", test_ziplistCreateLongListAndCheckIndices}, {"test_ziplistCompareStringWithZiplistEntries", test_ziplistCompareStringWithZiplistEntries}, {"test_ziplistMergeTest", test_ziplistMergeTest}, {"test_ziplistStressWithRandomPayloadsOfDifferentEncoding", test_ziplistStressWithRandomPayloadsOfDifferentEncoding}, {"test_ziplistCascadeUpdateEdgeCases", test_ziplistCascadeUpdateEdgeCases}, {"test_ziplistInsertEdgeCase", test_ziplistInsertEdgeCase}, {"test_ziplistStressWithVariableSize", test_ziplistStressWithVariableSize}, {"test_BenchmarkziplistFind", test_BenchmarkziplistFind}, {"test_BenchmarkziplistIndex", test_BenchmarkziplistIndex}, {"test_BenchmarkziplistValidateIntegrity", test_BenchmarkziplistValidateIntegrity}, {"test_BenchmarkziplistCompareWithString", test_BenchmarkziplistCompareWithString}, {"test_BenchmarkziplistCompareWithNumber", test_BenchmarkziplistCompareWithNumber}, {"test_ziplistStress__ziplistCascadeUpdate", test_ziplistStress__ziplistCascadeUpdate}, {NULL, NULL}};

src/unit/test_util.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,30 @@ int test_reclaimFilePageCache(int argc, char **argv, int flags) {
330330
#endif
331331
return 0;
332332
}
333+
334+
int test_writePointerWithPadding(int argc, char **argv, int flags) {
335+
UNUSED(argc);
336+
UNUSED(argv);
337+
UNUSED(flags);
338+
339+
unsigned char buf[8];
340+
static int dummy;
341+
void *ptr = &dummy;
342+
size_t ptr_size = sizeof(ptr);
343+
344+
/* Write the pointer and pad to 8 bytes */
345+
writePointerWithPadding(buf, ptr);
346+
347+
/* The first ptr_size bytes must match the raw pointer bytes */
348+
unsigned char expected[sizeof(ptr)];
349+
memcpy(expected, &ptr, ptr_size);
350+
TEST_ASSERT(memcmp(buf, expected, ptr_size) == 0);
351+
352+
353+
/* The remaining bytes (if any) must be zero */
354+
for (size_t i = ptr_size; i < sizeof(buf); i++) {
355+
TEST_ASSERT(buf[i] == 0);
356+
}
357+
358+
return 0;
359+
}

src/util.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,3 +1570,12 @@ int snprintf_async_signal_safe(char *to, size_t n, const char *fmt, ...) {
15701570
va_end(args);
15711571
return result;
15721572
}
1573+
1574+
/* Writes a pointer into an 8 bytes field, padding with zeros on 32bit targets
1575+
* to ensure a consistent fixed width encoding. */
1576+
void writePointerWithPadding(unsigned char *buf, const void *ptr) {
1577+
size_t ptr_size = sizeof(ptr); /* 4 on 32‑bit, 8 on 64‑bit */
1578+
memcpy(buf, &ptr, ptr_size);
1579+
/* if it is 32-bit system, pad the remaining 4 bytes with zero */
1580+
if (ptr_size == 4) memset(buf + ptr_size, 0, ptr_size);
1581+
}

src/util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,6 @@ void getRandomSeedCString(char *buff, size_t len);
103103
void setRandomSeedCString(char *seed_str, size_t len);
104104
void getRandomHexChars(char *p, size_t len);
105105
void getRandomBytes(unsigned char *p, size_t len);
106+
void writePointerWithPadding(unsigned char *buf, const void *ptr);
106107

107108
#endif

0 commit comments

Comments
 (0)