Unverified Commit 93e85347 authored by yoav-steinberg's avatar yoav-steinberg Committed by GitHub
Browse files

Remove argument count limit, dynamically grow argv. (#9528)

Remove hard coded multi-bulk limit (was 1,048,576), new limit is INT_MAX.
When client sends an m-bulk that's higher than 1024, we initially only allocate
the argv array for 1024 arguments, and gradually grow that allocation as arguments
are received.
parent dd3ac97f
......@@ -138,6 +138,7 @@ client *createClient(connection *conn) {
c->reqtype = 0;
c->argc = 0;
c->argv = NULL;
c->argv_len = 0;
c->argv_len_sum = 0;
c->original_argc = 0;
c->original_argv = NULL;
......@@ -1209,6 +1210,9 @@ void freeClientArgv(client *c) {
c->argc = 0;
c->cmd = NULL;
c->argv_len_sum = 0;
c->argv_len = 0;
zfree(c->argv);
c->argv = NULL;
}
/* Close all the slaves connections. This is useful in chained replication
......@@ -1446,8 +1450,6 @@ void freeClient(client *c) {
/* Release other dynamically allocated client structure fields,
* and finally release the client structure itself. */
if (c->name) decrRefCount(c->name);
zfree(c->argv);
c->argv_len_sum = 0;
freeClientMultiState(c);
sdsfree(c->peerid);
sdsfree(c->sockname);
......@@ -1821,7 +1823,8 @@ int processInlineBuffer(client *c) {
/* Setup argv array on client structure */
if (argc) {
if (c->argv) zfree(c->argv);
c->argv = zmalloc(sizeof(robj*)*argc);
c->argv_len = argc;
c->argv = zmalloc(sizeof(robj*)*c->argv_len);
c->argv_len_sum = 0;
}
......@@ -1906,7 +1909,7 @@ int processMultibulkBuffer(client *c) {
* so go ahead and find out the multi bulk length. */
serverAssertWithInfo(c,NULL,c->querybuf[c->qb_pos] == '*');
ok = string2ll(c->querybuf+1+c->qb_pos,newline-(c->querybuf+1+c->qb_pos),&ll);
if (!ok || ll > 1024*1024) {
if (!ok || ll > INT_MAX) {
addReplyError(c,"Protocol error: invalid multibulk length");
setProtocolError("invalid mbulk count",c);
return C_ERR;
......@@ -1920,7 +1923,8 @@ int processMultibulkBuffer(client *c) {
/* Setup argv array on client structure */
if (c->argv) zfree(c->argv);
c->argv = zmalloc(sizeof(robj*)*c->multibulklen);
c->argv_len = min(c->multibulklen, 1024);
c->argv = zmalloc(sizeof(robj*)*c->argv_len);
c->argv_len_sum = 0;
}
......@@ -1986,6 +1990,12 @@ int processMultibulkBuffer(client *c) {
/* Not enough data (+2 == trailing \r\n) */
break;
} else {
/* Check if we have space in argv, grow if needed */
if (c->argc >= c->argv_len) {
c->argv_len = min(c->argv_len < INT_MAX/2 ? c->argv_len*2 : INT_MAX, c->argc+c->multibulklen);
c->argv = zrealloc(c->argv, sizeof(robj*)*c->argv_len);
}
/* Optimization: if the buffer contains JUST our bulk element
* instead of creating a new object by *copying* the sds we
* just use the current sds string. */
......@@ -3186,9 +3196,9 @@ void replaceClientCommandVector(client *c, int argc, robj **argv) {
void rewriteClientCommandArgument(client *c, int i, robj *newval) {
robj *oldval;
retainOriginalCommandVector(c);
if (i >= c->argc) {
if (i >= c->argv_len) {
c->argv = zrealloc(c->argv,sizeof(robj*)*(i+1));
c->argc = i+1;
c->argc = c->argv_len = i+1;
c->argv[i] = NULL;
}
oldval = c->argv[i];
......
......@@ -939,6 +939,7 @@ typedef struct client {
size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size. */
int argc; /* Num of arguments of current command. */
robj **argv; /* Arguments of current command. */
int argv_len; /* Size of argv array (may be more than argc) */
int original_argc; /* Num of arguments of original command if arguments were rewritten. */
robj **original_argv; /* Arguments of original command if arguments were rewritten. */
size_t argv_len_sum; /* Sum of lengths of objects in argv list. */
......
......@@ -15,7 +15,7 @@ start_server {tags {"protocol network"}} {
test "Out of range multibulk length" {
reconnect
r write "*20000000\r\n"
r write "*3000000000\r\n"
r flush
assert_error "*invalid multibulk length*" {r read}
}
......@@ -196,6 +196,14 @@ start_server {tags {"protocol network"}} {
r debug protocol verbatim
} "This is a verbatim\nstring" {needs:debug resp3}
test "test large number of args" {
r flushdb
set args [split [string trim [string repeat "k v " 10000]]]
lappend args "{k}2" v2
r mset {*}$args
assert_equal [r get "{k}2"] v2
}
}
start_server {tags {"regression"}} {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment