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 /read.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 'read.c')
-rw-r--r-- | read.c | 38 |
1 files changed, 20 insertions, 18 deletions
@@ -42,6 +42,7 @@ #include <limits.h> #include <math.h> +#include "alloc.h" #include "read.h" #include "sds.h" #include "win32.h" @@ -425,7 +426,7 @@ static int redisReaderGrow(redisReader *r) { /* Grow our stack size */ newlen = r->tasks + REDIS_READER_STACK_SIZE; - aux = realloc(r->task, sizeof(*r->task) * newlen); + aux = hi_realloc(r->task, sizeof(*r->task) * newlen); if (aux == NULL) goto oom; @@ -433,7 +434,7 @@ static int redisReaderGrow(redisReader *r) { /* Allocate new tasks */ for (; r->tasks < newlen; r->tasks++) { - r->task[r->tasks] = calloc(1, sizeof(**r->task)); + r->task[r->tasks] = hi_calloc(1, sizeof(**r->task)); if (r->task[r->tasks] == NULL) goto oom; } @@ -467,7 +468,9 @@ static int processAggregateItem(redisReader *r) { root = (r->ridx == 0); - if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) { + if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) || + (r->maxelements > 0 && elements > r->maxelements)) + { __redisReaderSetError(r,REDIS_ERR_PROTOCOL, "Multi-bulk length out of range"); return REDIS_ERR; @@ -602,7 +605,7 @@ static int processItem(redisReader *r) { redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { redisReader *r; - r = calloc(1,sizeof(redisReader)); + r = hi_calloc(1,sizeof(redisReader)); if (r == NULL) return NULL; @@ -610,22 +613,22 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { if (r->buf == NULL) goto oom; - r->task = calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task)); + r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task)); if (r->task == NULL) goto oom; for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) { - r->task[r->tasks] = calloc(1, sizeof(**r->task)); + r->task[r->tasks] = hi_calloc(1, sizeof(**r->task)); if (r->task[r->tasks] == NULL) goto oom; } r->fn = fn; r->maxbuf = REDIS_READER_MAX_BUF; - + r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS; r->ridx = -1; - return r; + return r; oom: redisReaderFree(r); return NULL; @@ -640,14 +643,14 @@ void redisReaderFree(redisReader *r) { /* We know r->task[i] is allocatd if i < r->tasks */ for (int i = 0; i < r->tasks; i++) { - free(r->task[i]); + hi_free(r->task[i]); } if (r->task) - free(r->task); + hi_free(r->task); sdsfree(r->buf); - free(r); + hi_free(r); } int redisReaderFeed(redisReader *r, const char *buf, size_t len) { @@ -663,23 +666,22 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) { if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { sdsfree(r->buf); r->buf = sdsempty(); - r->pos = 0; + if (r->buf == 0) goto oom; - /* r->buf should not be NULL since we just free'd a larger one. */ - assert(r->buf != NULL); + r->pos = 0; } newbuf = sdscatlen(r->buf,buf,len); - if (newbuf == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } + if (newbuf == NULL) goto oom; r->buf = newbuf; r->len = sdslen(r->buf); } return REDIS_OK; +oom: + __redisReaderSetErrorOOM(r); + return REDIS_ERR; } int redisReaderGetReply(redisReader *r, void **reply) { |