summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/acl.c2
-rw-r--r--src/module.c9
-rw-r--r--src/networking.c13
-rw-r--r--src/redis-benchmark.c2
-rw-r--r--src/server.h1
-rw-r--r--tests/unit/acl.tcl7
6 files changed, 25 insertions, 9 deletions
diff --git a/src/acl.c b/src/acl.c
index d9f431f4f..0205e51ad 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -542,6 +542,8 @@ struct redisCommand *ACLLookupCommand(const char *name) {
* and command ID. */
void ACLResetSubcommandsForCommand(user *u, unsigned long id) {
if (u->allowed_subcommands && u->allowed_subcommands[id]) {
+ for (int i = 0; u->allowed_subcommands[id][i]; i++)
+ sdsfree(u->allowed_subcommands[id][i]);
zfree(u->allowed_subcommands[id]);
u->allowed_subcommands[id] = NULL;
}
diff --git a/src/module.c b/src/module.c
index f468d4996..c29521670 100644
--- a/src/module.c
+++ b/src/module.c
@@ -3747,14 +3747,7 @@ void moduleHandleBlockedClients(void) {
* replies to send to the client in a thread safe context.
* We need to glue such replies to the client output buffer and
* free the temporary client we just used for the replies. */
- if (c) {
- if (bc->reply_client->bufpos)
- addReplyProto(c,bc->reply_client->buf,
- bc->reply_client->bufpos);
- if (listLength(bc->reply_client->reply))
- listJoin(c->reply,bc->reply_client->reply);
- c->reply_bytes += bc->reply_client->reply_bytes;
- }
+ if (c) AddReplyFromClient(c, bc->reply_client);
freeClient(bc->reply_client);
if (c != NULL) {
diff --git a/src/networking.c b/src/networking.c
index 09cbff387..7fdd1984d 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -744,6 +744,19 @@ void addReplySubcommandSyntaxError(client *c) {
sdsfree(cmd);
}
+/* Append 'src' client output buffers into 'dst' client output buffers.
+ * This function clears the output buffers of 'src' */
+void AddReplyFromClient(client *dst, client *src) {
+ if (prepareClientToWrite(dst) != C_OK)
+ return;
+ addReplyProto(dst,src->buf, src->bufpos);
+ if (listLength(src->reply))
+ listJoin(dst->reply,src->reply);
+ dst->reply_bytes += src->reply_bytes;
+ src->reply_bytes = 0;
+ src->bufpos = 0;
+}
+
/* Copy 'src' client output buffers into 'dst' client output buffers.
* The function takes care of freeing the old output buffers of the
* destination client. */
diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c
index 12e9f7e41..4e2662f21 100644
--- a/src/redis-benchmark.c
+++ b/src/redis-benchmark.c
@@ -1192,7 +1192,7 @@ static int fetchClusterSlotsConfiguration(client c) {
assert(reply->type == REDIS_REPLY_ARRAY);
for (i = 0; i < reply->elements; i++) {
redisReply *r = reply->element[i];
- assert(r->type = REDIS_REPLY_ARRAY);
+ assert(r->type == REDIS_REPLY_ARRAY);
assert(r->elements >= 3);
int from, to, slot;
from = r->element[0]->integer;
diff --git a/src/server.h b/src/server.h
index 95e0355a6..dfd9f7698 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1529,6 +1529,7 @@ void addReplyNullArray(client *c);
void addReplyBool(client *c, int b);
void addReplyVerbatim(client *c, const char *s, size_t len, const char *ext);
void addReplyProto(client *c, const char *s, size_t len);
+void AddReplyFromClient(client *c, client *src);
void addReplyBulk(client *c, robj *obj);
void addReplyBulkCString(client *c, const char *s);
void addReplyBulkCBuffer(client *c, const void *p, size_t len);
diff --git a/tests/unit/acl.tcl b/tests/unit/acl.tcl
index 82c75f82d..058441433 100644
--- a/tests/unit/acl.tcl
+++ b/tests/unit/acl.tcl
@@ -108,4 +108,11 @@ start_server {tags {"acl"}} {
assert_match {*+debug|segfault*} $cmdstr
assert_match {*+acl*} $cmdstr
}
+
+ test {ACL #5998 regression: memory leaks adding / removing subcommands} {
+ r AUTH default ""
+ r ACL setuser newuser reset -debug +debug|a +debug|b +debug|c
+ r ACL setuser newuser -debug
+ # The test framework will detect a leak if any.
+ }
}