From a15378861368a4267c2c2c73b90db2849f943ebd Mon Sep 17 00:00:00 2001 From: Michael Grunder Date: Tue, 28 Jan 2020 12:13:05 -0800 Subject: [PATCH] Safe allocation wrappers (#754) Create allocation wrappers with a configurable OOM handler (defaults to abort()). See #752, #747 --- Makefile | 17 ++++++------ adapters/ae.h | 2 +- adapters/ivykis.h | 2 +- adapters/libev.h | 2 +- adapters/libevent.h | 2 +- alloc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ alloc.h | 53 ++++++++++++++++++++++++++++++++++++ async.c | 3 ++- dict.c | 7 ++--- hiredis.h | 1 + net.c | 10 +++---- 11 files changed, 143 insertions(+), 21 deletions(-) create mode 100644 alloc.c create mode 100644 alloc.h diff --git a/Makefile b/Makefile index b2e45f058..d1f005af4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # Copyright (C) 2010-2011 Pieter Noordhuis # This file is released under the BSD license, see the COPYING file -OBJ=net.o hiredis.o sds.o async.o read.o +OBJ=net.o hiredis.o sds.o async.o read.o alloc.o EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib TESTS=hiredis-test LIBNAME=libhiredis @@ -68,13 +68,14 @@ endif all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) # Deps (use make dep to generate this) -async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h -dict.o: dict.c fmacros.h dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h +alloc.o: alloc.c fmacros.h alloc.h +async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h +dict.o: dict.c fmacros.h alloc.h dict.h +hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h +net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h read.o: read.c fmacros.h read.h sds.h -sds.o: sds.c sds.h -test.o: test.c fmacros.h hiredis.h read.h sds.h +sds.o: sds.c sds.h sdsalloc.h +test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h $(DYLIBNAME): $(OBJ) $(DYLIB_MAKE_CMD) $(OBJ) @@ -177,7 +178,7 @@ $(PKGCONFNAME): hiredis.h install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h $(INSTALL_INCLUDE_PATH) + $(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH) $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) diff --git a/adapters/ae.h b/adapters/ae.h index 5c551c2ed..03939928d 100644 --- a/adapters/ae.h +++ b/adapters/ae.h @@ -108,7 +108,7 @@ static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { return REDIS_ERR; /* Create container for context and r/w events */ - e = (redisAeEvents*)malloc(sizeof(*e)); + e = (redisAeEvents*)hi_malloc(sizeof(*e)); e->context = ac; e->loop = loop; e->fd = c->fd; diff --git a/adapters/ivykis.h b/adapters/ivykis.h index 6a12a868a..75616ee24 100644 --- a/adapters/ivykis.h +++ b/adapters/ivykis.h @@ -55,7 +55,7 @@ static int redisIvykisAttach(redisAsyncContext *ac) { return REDIS_ERR; /* Create container for context and r/w events */ - e = (redisIvykisEvents*)malloc(sizeof(*e)); + e = (redisIvykisEvents*)hi_malloc(sizeof(*e)); e->context = ac; /* Register functions to start/stop listening for events */ diff --git a/adapters/libev.h b/adapters/libev.h index 2bf8d521f..abad43634 100644 --- a/adapters/libev.h +++ b/adapters/libev.h @@ -119,7 +119,7 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { return REDIS_ERR; /* Create container for context and r/w events */ - e = (redisLibevEvents*)malloc(sizeof(*e)); + e = (redisLibevEvents*)hi_malloc(sizeof(*e)); e->context = ac; #if EV_MULTIPLICITY e->loop = loop; diff --git a/adapters/libevent.h b/adapters/libevent.h index 7d2bef180..f2330d6f0 100644 --- a/adapters/libevent.h +++ b/adapters/libevent.h @@ -87,7 +87,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { return REDIS_ERR; /* Create container for context and r/w events */ - e = (redisLibeventEvents*)malloc(sizeof(*e)); + e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e)); e->context = ac; /* Register functions to start/stop listening for events */ diff --git a/alloc.c b/alloc.c new file mode 100644 index 000000000..55c3020e7 --- /dev/null +++ b/alloc.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, Michael Grunder + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmacros.h" +#include "alloc.h" +#include + +void *hi_malloc(size_t size) { + void *ptr = malloc(size); + if (ptr == NULL) + HIREDIS_OOM_HANDLER; + + return ptr; +} + +void *hi_calloc(size_t nmemb, size_t size) { + void *ptr = calloc(nmemb, size); + if (ptr == NULL) + HIREDIS_OOM_HANDLER; + + return ptr; +} + +void *hi_realloc(void *ptr, size_t size) { + void *newptr = realloc(ptr, size); + if (newptr == NULL) + HIREDIS_OOM_HANDLER; + + return newptr; +} + +char *hi_strdup(const char *str) { + char *newstr = strdup(str); + if (newstr == NULL) + HIREDIS_OOM_HANDLER; + + return newstr; +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 000000000..2c9b04e35 --- /dev/null +++ b/alloc.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020, Michael Grunder + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HIREDIS_ALLOC_H +#define HIREDIS_ALLOC_H + +#include /* for size_t */ + +#ifndef HIREDIS_OOM_HANDLER +#define HIREDIS_OOM_HANDLER abort() +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void *hi_malloc(size_t size); +void *hi_calloc(size_t nmemb, size_t size); +void *hi_realloc(void *ptr, size_t size); +char *hi_strdup(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* HIREDIS_ALLOC_H */ diff --git a/async.c b/async.c index cb5b8415e..0018e3743 100644 --- a/async.c +++ b/async.c @@ -30,6 +30,7 @@ */ #include "fmacros.h" +#include "alloc.h" #include #include #include @@ -68,7 +69,7 @@ static unsigned int callbackHash(const void *key) { static void *callbackValDup(void *privdata, const void *src) { ((void) privdata); - redisCallback *dup = malloc(sizeof(*dup)); + redisCallback *dup = hi_malloc(sizeof(*dup)); memcpy(dup,src,sizeof(*dup)); return dup; } diff --git a/dict.c b/dict.c index e17a62546..29cdc190f 100644 --- a/dict.c +++ b/dict.c @@ -34,6 +34,7 @@ */ #include "fmacros.h" +#include "alloc.h" #include #include #include @@ -71,7 +72,7 @@ static void _dictReset(dict *ht) { /* Create a new hash table */ static dict *dictCreate(dictType *type, void *privDataPtr) { - dict *ht = malloc(sizeof(*ht)); + dict *ht = hi_malloc(sizeof(*ht)); _dictInit(ht,type,privDataPtr); return ht; } @@ -142,7 +143,7 @@ static int dictAdd(dict *ht, void *key, void *val) { return DICT_ERR; /* Allocates the memory and stores key */ - entry = malloc(sizeof(*entry)); + entry = hi_malloc(sizeof(*entry)); entry->next = ht->table[index]; ht->table[index] = entry; @@ -256,7 +257,7 @@ static dictEntry *dictFind(dict *ht, const void *key) { } static dictIterator *dictGetIterator(dict *ht) { - dictIterator *iter = malloc(sizeof(*iter)); + dictIterator *iter = hi_malloc(sizeof(*iter)); iter->ht = ht; iter->index = -1; diff --git a/hiredis.h b/hiredis.h index bd53e7ec0..1c0c76aee 100644 --- a/hiredis.h +++ b/hiredis.h @@ -38,6 +38,7 @@ #include /* for struct timeval */ #include /* uintXX_t, etc */ #include "sds.h" /* for sds */ +#include "alloc.h" /* for allocation wrappers */ #define HIREDIS_MAJOR 0 #define HIREDIS_MINOR 14 diff --git a/net.c b/net.c index 5d50f7ce4..d71bbcd57 100644 --- a/net.c +++ b/net.c @@ -287,13 +287,13 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, if (c->tcp.host != addr) { free(c->tcp.host); - c->tcp.host = strdup(addr); + c->tcp.host = hi_strdup(addr); } if (timeout) { if (c->timeout != timeout) { if (c->timeout == NULL) - c->timeout = malloc(sizeof(struct timeval)); + c->timeout = hi_malloc(sizeof(struct timeval)); memcpy(c->timeout, timeout, sizeof(struct timeval)); } @@ -312,7 +312,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, c->tcp.source_addr = NULL; } else if (c->tcp.source_addr != source_addr) { free(c->tcp.source_addr); - c->tcp.source_addr = strdup(source_addr); + c->tcp.source_addr = hi_strdup(source_addr); } snprintf(_port, 6, "%d", port); @@ -440,12 +440,12 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time c->connection_type = REDIS_CONN_UNIX; if (c->unix_sock.path != path) - c->unix_sock.path = strdup(path); + c->unix_sock.path = hi_strdup(path); if (timeout) { if (c->timeout != timeout) { if (c->timeout == NULL) - c->timeout = malloc(sizeof(struct timeval)); + c->timeout = hi_malloc(sizeof(struct timeval)); memcpy(c->timeout, timeout, sizeof(struct timeval)); }