diff options
author | Michael Grunder <michael.grunder@gmail.com> | 2020-05-22 09:27:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-22 09:27:49 -0700 |
commit | 8e0264cfd6889b73c241b60736fe96ba1322ee6e (patch) | |
tree | c7a8f050a2e6966c45f7af919056b9653f831579 /hiredis.c | |
parent | 83bba659b9dbd6c77baf2ff27ff6342317869a3e (diff) |
Allow users to replace allocator and handle OOM everywhere. (#800)
* Adds an indirection to every allocation/deallocation to allow users to
plug in ones of their choosing (use custom functions, jemalloc, etc).
* Gracefully handle OOM everywhere in hiredis. This should make it possible
for users of the library to have more flexibility in how they handle such situations.
* Changes `redisReaderTask->elements` from an `int` to a `long long` to prevent
a possible overflow when transferring the task elements into a `redisReply`.
* Adds a configurable `max elements` member to `redisReader` that defaults to
2^32 - 1. This can be set to "unlimited" by setting the value to zero.
Diffstat (limited to 'hiredis.c')
-rw-r--r-- | hiredis.c | 87 |
1 files changed, 51 insertions, 36 deletions
@@ -74,7 +74,7 @@ static redisReplyObjectFunctions defaultFunctions = { /* Create a reply object */ static redisReply *createReplyObject(int type) { - redisReply *r = calloc(1,sizeof(*r)); + redisReply *r = hi_calloc(1,sizeof(*r)); if (r == NULL) return NULL; @@ -101,7 +101,7 @@ void freeReplyObject(void *reply) { if (r->element != NULL) { for (j = 0; j < r->elements; j++) freeReplyObject(r->element[j]); - free(r->element); + hi_free(r->element); } break; case REDIS_REPLY_ERROR: @@ -109,10 +109,10 @@ void freeReplyObject(void *reply) { case REDIS_REPLY_STRING: case REDIS_REPLY_DOUBLE: case REDIS_REPLY_VERB: - free(r->str); + hi_free(r->str); break; } - free(r); + hi_free(r); } static void *createStringObject(const redisReadTask *task, char *str, size_t len) { @@ -130,22 +130,18 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len /* Copy string value */ if (task->type == REDIS_REPLY_VERB) { - buf = malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */ - if (buf == NULL) { - freeReplyObject(r); - return NULL; - } + buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */ + if (buf == NULL) goto oom; + memcpy(r->vtype,str,3); r->vtype[3] = '\0'; memcpy(buf,str+4,len-4); buf[len-4] = '\0'; r->len = len - 4; } else { - buf = malloc(len+1); - if (buf == NULL) { - freeReplyObject(r); - return NULL; - } + buf = hi_malloc(len+1); + if (buf == NULL) goto oom; + memcpy(buf,str,len); buf[len] = '\0'; r->len = len; @@ -161,6 +157,10 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len parent->element[task->idx] = r; } return r; + +oom: + freeReplyObject(r); + return NULL; } static void *createArrayObject(const redisReadTask *task, size_t elements) { @@ -171,7 +171,7 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) { return NULL; if (elements > 0) { - r->element = calloc(elements,sizeof(redisReply*)); + r->element = hi_calloc(elements,sizeof(redisReply*)); if (r->element == NULL) { freeReplyObject(r); return NULL; @@ -218,7 +218,7 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s return NULL; r->dval = value; - r->str = malloc(len+1); + r->str = hi_malloc(len+1); if (r->str == NULL) { freeReplyObject(r); return NULL; @@ -322,7 +322,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { if (*c != '%' || c[1] == '\0') { if (*c == ' ') { if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); + newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto memory_err; curargv = newargv; curargv[argc++] = curarg; @@ -471,7 +471,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { /* Add the last argument if needed */ if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); + newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto memory_err; curargv = newargv; curargv[argc++] = curarg; @@ -487,7 +487,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { totlen += 1+countDigits(argc)+2; /* Build the command at protocol level */ - cmd = malloc(totlen+1); + cmd = hi_malloc(totlen+1); if (cmd == NULL) goto memory_err; pos = sprintf(cmd,"*%d\r\n",argc); @@ -502,7 +502,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { assert(pos == totlen); cmd[pos] = '\0'; - free(curargv); + hi_free(curargv); *target = cmd; return totlen; @@ -518,11 +518,11 @@ cleanup: if (curargv) { while(argc--) sdsfree(curargv[argc]); - free(curargv); + hi_free(curargv); } sdsfree(curarg); - free(cmd); + hi_free(cmd); return error_type; } @@ -563,7 +563,7 @@ int redisFormatCommand(char **target, const char *format, ...) { int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, const size_t *argvlen) { - sds cmd; + sds cmd, aux; unsigned long long totlen; int j; size_t len; @@ -585,9 +585,13 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, return -1; /* We already know how much storage we need */ - cmd = sdsMakeRoomFor(cmd, totlen); - if (cmd == NULL) + aux = sdsMakeRoomFor(cmd, totlen); + if (aux == NULL) { + sdsfree(cmd); return -1; + } + + cmd = aux; /* Construct command */ cmd = sdscatfmt(cmd, "*%i\r\n", argc); @@ -631,7 +635,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz } /* Build the command at protocol level */ - cmd = malloc(totlen+1); + cmd = hi_malloc(totlen+1); if (cmd == NULL) return -1; @@ -652,7 +656,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz } void redisFreeCommand(char *cmd) { - free(cmd); + hi_free(cmd); } void __redisSetError(redisContext *c, int type, const char *str) { @@ -678,7 +682,7 @@ redisReader *redisReaderCreate(void) { static redisContext *redisContextInit(const redisOptions *options) { redisContext *c; - c = calloc(1, sizeof(*c)); + c = hi_calloc(1, sizeof(*c)); if (c == NULL) return NULL; @@ -702,16 +706,16 @@ void redisFree(redisContext *c) { sdsfree(c->obuf); redisReaderFree(c->reader); - free(c->tcp.host); - free(c->tcp.source_addr); - free(c->unix_sock.path); - free(c->timeout); - free(c->saddr); + hi_free(c->tcp.host); + hi_free(c->tcp.source_addr); + hi_free(c->unix_sock.path); + hi_free(c->timeout); + hi_free(c->saddr); if (c->funcs->free_privdata) { c->funcs->free_privdata(c->privdata); } memset(c, 0xff, sizeof(*c)); - free(c); + hi_free(c); } redisFD redisFreeKeepFd(redisContext *c) { @@ -738,6 +742,11 @@ int redisReconnect(redisContext *c) { c->obuf = sdsempty(); c->reader = redisReaderCreate(); + if (c->obuf == NULL || c->reader == NULL) { + __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + if (c->connection_type == REDIS_CONN_TCP) { return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, c->timeout, c->tcp.source_addr); @@ -918,6 +927,8 @@ int redisBufferWrite(redisContext *c, int *done) { if (nwritten == (signed)sdslen(c->obuf)) { sdsfree(c->obuf); c->obuf = sdsempty(); + if (c->obuf == NULL) + goto oom; } else { sdsrange(c->obuf,nwritten,-1); } @@ -925,6 +936,10 @@ int redisBufferWrite(redisContext *c, int *done) { } if (done != NULL) *done = (sdslen(c->obuf) == 0); return REDIS_OK; + +oom: + __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; } /* Internal helper function to try and get a reply from the reader, @@ -1015,11 +1030,11 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { } if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - free(cmd); + hi_free(cmd); return REDIS_ERR; } - free(cmd); + hi_free(cmd); return REDIS_OK; } |