summaryrefslogtreecommitdiff
path: root/src/zmalloc.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/zmalloc.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/zmalloc.c')
-rw-r--r--src/zmalloc.c152
1 files changed, 88 insertions, 64 deletions
diff --git a/src/zmalloc.c b/src/zmalloc.c
index 7425198fe..a04ecacae 100644
--- a/src/zmalloc.c
+++ b/src/zmalloc.c
@@ -85,33 +85,44 @@ static void zmalloc_default_oom(size_t size) {
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
-void *zmalloc(size_t size) {
+/* Try allocating memory, and return NULL if failed.
+ * '*usable' is set to the usable size if non NULL. */
+void *ztrymalloc_usable(size_t size, size_t *usable) {
void *ptr = malloc(size+PREFIX_SIZE);
- if (!ptr) zmalloc_oom_handler(size);
+ if (!ptr) return NULL;
#ifdef HAVE_MALLOC_SIZE
- update_zmalloc_stat_alloc(zmalloc_size(ptr));
+ size = zmalloc_size(ptr);
+ update_zmalloc_stat_alloc(size);
+ if (usable) *usable = size;
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
+ if (usable) *usable = size;
return (char*)ptr+PREFIX_SIZE;
#endif
}
-/* Similar to zmalloc, '*usable' is set to the usable size. */
-void *zmalloc_usable(size_t size, size_t *usable) {
- void *ptr = malloc(size+PREFIX_SIZE);
+/* Allocate memory or panic */
+void *zmalloc(size_t size) {
+ void *ptr = ztrymalloc_usable(size, NULL);
+ if (!ptr) zmalloc_oom_handler(size);
+ return ptr;
+}
+/* Try allocating memory, and return NULL if failed. */
+void *ztrymalloc(size_t size) {
+ void *ptr = ztrymalloc_usable(size, NULL);
+ return ptr;
+}
+
+/* Allocate memory or panic.
+ * '*usable' is set to the usable size if non NULL. */
+void *zmalloc_usable(size_t size, size_t *usable) {
+ void *ptr = ztrymalloc_usable(size, usable);
if (!ptr) zmalloc_oom_handler(size);
-#ifdef HAVE_MALLOC_SIZE
- update_zmalloc_stat_alloc(*usable = zmalloc_size(ptr));
return ptr;
-#else
- *((size_t*)ptr) = *usable = size;
- update_zmalloc_stat_alloc(size+PREFIX_SIZE);
- return (char*)ptr+PREFIX_SIZE;
-#endif
}
/* Allocation and free functions that bypass the thread cache
@@ -132,101 +143,114 @@ void zfree_no_tcache(void *ptr) {
}
#endif
-void *zcalloc(size_t size) {
+/* Try allocating memory and zero it, and return NULL if failed.
+ * '*usable' is set to the usable size if non NULL. */
+void *ztrycalloc_usable(size_t size, size_t *usable) {
void *ptr = calloc(1, size+PREFIX_SIZE);
+ if (ptr == NULL) return NULL;
- if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
- update_zmalloc_stat_alloc(zmalloc_size(ptr));
+ size = zmalloc_size(ptr);
+ update_zmalloc_stat_alloc(size);
+ if (usable) *usable = size;
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
+ if (usable) *usable = size;
return (char*)ptr+PREFIX_SIZE;
#endif
}
-/* Similar to zcalloc, '*usable' is set to the usable size. */
-void *zcalloc_usable(size_t size, size_t *usable) {
- void *ptr = calloc(1, size+PREFIX_SIZE);
+/* Allocate memory and zero it or panic */
+void *zcalloc(size_t size) {
+ void *ptr = ztrycalloc_usable(size, NULL);
+ if (!ptr) zmalloc_oom_handler(size);
+ return ptr;
+}
+
+/* Try allocating memory, and return NULL if failed. */
+void *ztrycalloc(size_t size) {
+ void *ptr = ztrycalloc_usable(size, NULL);
+ return ptr;
+}
+/* Allocate memory or panic.
+ * '*usable' is set to the usable size if non NULL. */
+void *zcalloc_usable(size_t size, size_t *usable) {
+ void *ptr = ztrycalloc_usable(size, usable);
if (!ptr) zmalloc_oom_handler(size);
-#ifdef HAVE_MALLOC_SIZE
- update_zmalloc_stat_alloc(*usable = zmalloc_size(ptr));
return ptr;
-#else
- *((size_t*)ptr) = *usable = size;
- update_zmalloc_stat_alloc(size+PREFIX_SIZE);
- return (char*)ptr+PREFIX_SIZE;
-#endif
}
-void *zrealloc(void *ptr, size_t size) {
+/* Try reallocating memory, and return NULL if failed.
+ * '*usable' is set to the usable size if non NULL. */
+void *ztryrealloc_usable(void *ptr, size_t size, size_t *usable) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
#endif
size_t oldsize;
void *newptr;
+ /* not allocating anything, just redirect to free. */
if (size == 0 && ptr != NULL) {
zfree(ptr);
+ if (usable) *usable = 0;
return NULL;
}
- if (ptr == NULL) return zmalloc(size);
+ /* Not freeing anything, just redirect to malloc. */
+ if (ptr == NULL)
+ return ztrymalloc_usable(size, usable);
+
#ifdef HAVE_MALLOC_SIZE
oldsize = zmalloc_size(ptr);
newptr = realloc(ptr,size);
- if (!newptr) zmalloc_oom_handler(size);
+ if (newptr == NULL) {
+ if (usable) *usable = 0;
+ return NULL;
+ }
update_zmalloc_stat_free(oldsize);
- update_zmalloc_stat_alloc(zmalloc_size(newptr));
+ size = zmalloc_size(newptr);
+ update_zmalloc_stat_alloc(size);
+ if (usable) *usable = size;
return newptr;
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
newptr = realloc(realptr,size+PREFIX_SIZE);
- if (!newptr) zmalloc_oom_handler(size);
+ if (newptr == NULL) {
+ if (usable) *usable = 0;
+ return NULL;
+ }
*((size_t*)newptr) = size;
- update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
- update_zmalloc_stat_alloc(size+PREFIX_SIZE);
+ update_zmalloc_stat_free(oldsize);
+ update_zmalloc_stat_alloc(size);
+ if (usable) *usable = size;
return (char*)newptr+PREFIX_SIZE;
#endif
}
-/* Similar to zrealloc, '*usable' is set to the new usable size. */
-void *zrealloc_usable(void *ptr, size_t size, size_t *usable) {
-#ifndef HAVE_MALLOC_SIZE
- void *realptr;
-#endif
- size_t oldsize;
- void *newptr;
-
- if (size == 0 && ptr != NULL) {
- zfree(ptr);
- *usable = 0;
- return NULL;
- }
- if (ptr == NULL) return zmalloc_usable(size, usable);
-#ifdef HAVE_MALLOC_SIZE
- oldsize = zmalloc_size(ptr);
- newptr = realloc(ptr,size);
- if (!newptr) zmalloc_oom_handler(size);
+/* Reallocate memory and zero it or panic */
+void *zrealloc(void *ptr, size_t size) {
+ ptr = ztryrealloc_usable(ptr, size, NULL);
+ if (!ptr && size != 0) zmalloc_oom_handler(size);
+ return ptr;
+}
- update_zmalloc_stat_free(oldsize);
- update_zmalloc_stat_alloc(*usable = zmalloc_size(newptr));
- return newptr;
-#else
- realptr = (char*)ptr-PREFIX_SIZE;
- oldsize = *((size_t*)realptr);
- newptr = realloc(realptr,size+PREFIX_SIZE);
- if (!newptr) zmalloc_oom_handler(size);
+/* Try Reallocating memory, and return NULL if failed. */
+void *ztryrealloc(void *ptr, size_t size) {
+ ptr = ztryrealloc_usable(ptr, size, NULL);
+ return ptr;
+}
- *((size_t*)newptr) = *usable = size;
- update_zmalloc_stat_free(oldsize);
- update_zmalloc_stat_alloc(size);
- return (char*)newptr+PREFIX_SIZE;
-#endif
+/* Reallocate memory or panic.
+ * '*usable' is set to the usable size if non NULL. */
+void *zrealloc_usable(void *ptr, size_t size, size_t *usable) {
+ ptr = ztryrealloc_usable(ptr, size, usable);
+ if (!ptr && size != 0) zmalloc_oom_handler(size);
+ return ptr;
}
/* Provide zmalloc_size() for systems where this function is not provided by