summaryrefslogtreecommitdiff
path: root/hiredis.c
diff options
context:
space:
mode:
authorMichael Grunder <michael.grunder@gmail.com>2020-05-22 09:27:49 -0700
committerGitHub <noreply@github.com>2020-05-22 09:27:49 -0700
commit8e0264cfd6889b73c241b60736fe96ba1322ee6e (patch)
treec7a8f050a2e6966c45f7af919056b9653f831579 /hiredis.c
parent83bba659b9dbd6c77baf2ff27ff6342317869a3e (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.c87
1 files changed, 51 insertions, 36 deletions
diff --git a/hiredis.c b/hiredis.c
index 1c9e8ae..3133716 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -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;
}