From 669ac9d0c843f9ccf07d4969ff6bff75fafee01f 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 --- CMakeLists.txt | 3 ++- Makefile | 19 ++++++------- adapters/ae.h | 2 +- adapters/ivykis.h | 2 +- adapters/libev.h | 2 +- adapters/libevent.h | 2 +- alloc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ alloc.h | 44 ++++++++++++++++++++++++++++++ async.c | 5 ++-- dict.c | 7 ++--- hiredis.h | 1 + net.c | 14 +++++----- ssl.c | 2 +- 13 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 alloc.c create mode 100644 alloc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fcd8d4b..770e1a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,8 @@ ADD_LIBRARY(hiredis SHARED net.c read.c sds.c - sockcompat.c) + sockcompat.c + alloc.c) SET_TARGET_PROPERTIES(hiredis PROPERTIES diff --git a/Makefile b/Makefile index 25ac154..10a823c 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 sockcompat.o +OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o alloc.o SSL_OBJ=ssl.o EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib ifeq ($(USE_SSL),1) @@ -95,15 +95,16 @@ all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME) endif # 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 win32.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h sockcompat.h win32.h -read.o: read.c fmacros.h read.h sds.h -sds.o: sds.c sds.h +async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.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 async.h win32.h +alloc.o: alloc.c alloc.h +net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h +read.o: read.c fmacros.h read.h sds.h win32.h +sds.o: sds.c sds.h sdsalloc.h sockcompat.o: sockcompat.c sockcompat.h -ssl.o: ssl.c hiredis.h -test.o: test.c fmacros.h hiredis.h read.h sds.h +ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h async_private.h +test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h $(DYLIBNAME): $(OBJ) $(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS) diff --git a/adapters/ae.h b/adapters/ae.h index 5c551c2..0393992 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 6a12a86..75616ee 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 2bf8d52..abad436 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 a495277..0674ca6 100644 --- a/adapters/libevent.h +++ b/adapters/libevent.h @@ -152,7 +152,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { return REDIS_ERR; /* Create container for context and r/w events */ - e = (redisLibeventEvents*)calloc(1, 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 0000000..55c3020 --- /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 0000000..803129c --- /dev/null +++ b/alloc.h @@ -0,0 +1,44 @@ +/* + * 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 + +#include /* for size_t */ + +#ifndef HIREDIS_OOM_HANDLER +#define HIREDIS_OOM_HANDLER abort() +#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); + +#endif /* HIREDIS_ALLOC_H */ diff --git a/async.c b/async.c index 4f422d5..a966ed5 100644 --- a/async.c +++ b/async.c @@ -30,6 +30,7 @@ */ #include "fmacros.h" +#include "alloc.h" #include #include #ifndef _MSC_VER @@ -57,7 +58,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; } @@ -754,7 +755,7 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) { if (!ac->c.timeout) { - ac->c.timeout = calloc(1, sizeof(tv)); + ac->c.timeout = hi_calloc(1, sizeof(tv)); } if (tv.tv_sec == ac->c.timeout->tv_sec && diff --git a/dict.c b/dict.c index 5b349f0..eaf4e4d 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 bdc6670..9921e61 100644 --- a/hiredis.h +++ b/hiredis.h @@ -42,6 +42,7 @@ struct timeval; /* forward declaration */ #endif #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 e5f40b0..c928b33 100644 --- a/net.c +++ b/net.c @@ -358,13 +358,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)); } @@ -383,7 +383,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); @@ -447,7 +447,7 @@ addrretry: /* For repeat connection */ free(c->saddr); - c->saddr = malloc(p->ai_addrlen); + c->saddr = hi_malloc(p->ai_addrlen); memcpy(c->saddr, p->ai_addr, p->ai_addrlen); c->addrlen = p->ai_addrlen; @@ -526,12 +526,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)); } @@ -543,7 +543,7 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK) return REDIS_ERR; - sa = (struct sockaddr_un*)(c->saddr = malloc(sizeof(struct sockaddr_un))); + sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un))); c->addrlen = sizeof(struct sockaddr_un); sa->sun_family = AF_UNIX; strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1); diff --git a/ssl.c b/ssl.c index b97fc1d..e1e4aba 100644 --- a/ssl.c +++ b/ssl.c @@ -151,7 +151,7 @@ static void initOpensslLocks(void) { return; } nlocks = CRYPTO_num_locks(); - ossl_locks = malloc(sizeof(*ossl_locks) * nlocks); + ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks); for (ii = 0; ii < nlocks; ii++) { sslLockInit(ossl_locks + ii); }