summaryrefslogtreecommitdiff
path: root/read.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 /read.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 'read.c')
-rw-r--r--read.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/read.c b/read.c
index 4924014..d10b62a 100644
--- a/read.c
+++ b/read.c
@@ -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) {