summaryrefslogtreecommitdiff
path: root/src/dict.c
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2020-11-22 21:22:49 +0200
committerOran Agra <oran@redislabs.com>2020-12-06 14:54:34 +0200
commit7ca00d694d44be13a3ff9ff1c96b49222ac9463b (patch)
tree3567297f9a6e7b7730025024cf33c60d4ccf17de /src/dict.c
parent3716950cfc389c0f7ed13fac5bd205173c2d8189 (diff)
downloadredis-7ca00d694d44be13a3ff9ff1c96b49222ac9463b.tar.gz
Sanitize dump payload: fail RESTORE if memory allocation fails
When RDB input attempts to make a huge memory allocation that fails, RESTORE should fail gracefully rather than die with panic
Diffstat (limited to 'src/dict.c')
-rw-r--r--src/dict.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/dict.c b/src/dict.c
index cca5aa921..4736dacd5 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -143,9 +143,13 @@ int dictResize(dict *d)
return dictExpand(d, minimal);
}
-/* Expand or create the hash table */
-int dictExpand(dict *d, unsigned long size)
+/* Expand or create the hash table,
+ * when malloc_failed is non-NULL, it'll avoid panic if malloc fails (in which case it'll be set to 1).
+ * Returns DICT_OK if expand was performed, and DICT_ERR if skipped. */
+int _dictExpand(dict *d, unsigned long size, int* malloc_failed)
{
+ if (malloc_failed) *malloc_failed = 0;
+
/* the size is invalid if it is smaller than the number of
* elements already inside the hash table */
if (dictIsRehashing(d) || d->ht[0].used > size)
@@ -160,7 +164,14 @@ int dictExpand(dict *d, unsigned long size)
/* Allocate the new hash table and initialize all pointers to NULL */
n.size = realsize;
n.sizemask = realsize-1;
- n.table = zcalloc(realsize*sizeof(dictEntry*));
+ if (malloc_failed) {
+ n.table = ztrycalloc(realsize*sizeof(dictEntry*));
+ *malloc_failed = n.table == NULL;
+ if (*malloc_failed)
+ return DICT_ERR;
+ } else
+ n.table = zcalloc(realsize*sizeof(dictEntry*));
+
n.used = 0;
/* Is this the first initialization? If so it's not really a rehashing
@@ -176,6 +187,18 @@ int dictExpand(dict *d, unsigned long size)
return DICT_OK;
}
+/* return DICT_ERR if expand was not performed */
+int dictExpand(dict *d, unsigned long size) {
+ return _dictExpand(d, size, NULL);
+}
+
+/* return DICT_ERR if expand failed due to memory allocation failure */
+int dictTryExpand(dict *d, unsigned long size) {
+ int malloc_failed;
+ _dictExpand(d, size, &malloc_failed);
+ return malloc_failed? DICT_ERR : DICT_OK;
+}
+
/* Performs N steps of incremental rehashing. Returns 1 if there are still
* keys to move from the old to the new hash table, otherwise 0 is returned.
*