Safe allocation wrappers (#754)

Create allocation wrappers with a configurable OOM handler (defaults to abort()).

See #752, #747
This commit is contained in:
Michael Grunder 2020-01-28 12:13:05 -08:00 committed by GitHub
parent 0501c623c9
commit 669ac9d0c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 141 additions and 27 deletions

View File

@ -30,7 +30,8 @@ ADD_LIBRARY(hiredis SHARED
net.c net.c
read.c read.c
sds.c sds.c
sockcompat.c) sockcompat.c
alloc.c)
SET_TARGET_PROPERTIES(hiredis SET_TARGET_PROPERTIES(hiredis
PROPERTIES PROPERTIES

View File

@ -3,7 +3,7 @@
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com> # Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
# This file is released under the BSD license, see the COPYING file # 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 SSL_OBJ=ssl.o
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
ifeq ($(USE_SSL),1) ifeq ($(USE_SSL),1)
@ -95,15 +95,16 @@ all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
endif endif
# Deps (use make dep to generate this) # 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 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 dict.h dict.o: dict.c fmacros.h alloc.h dict.h
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h win32.h hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h sockcompat.h win32.h alloc.o: alloc.c alloc.h
read.o: read.c fmacros.h read.h sds.h net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h
sds.o: sds.c sds.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 sockcompat.o: sockcompat.c sockcompat.h
ssl.o: ssl.c hiredis.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 test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h
$(DYLIBNAME): $(OBJ) $(DYLIBNAME): $(OBJ)
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS) $(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)

View File

@ -108,7 +108,7 @@ static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
return REDIS_ERR; return REDIS_ERR;
/* Create container for context and r/w events */ /* Create container for context and r/w events */
e = (redisAeEvents*)malloc(sizeof(*e)); e = (redisAeEvents*)hi_malloc(sizeof(*e));
e->context = ac; e->context = ac;
e->loop = loop; e->loop = loop;
e->fd = c->fd; e->fd = c->fd;

View File

@ -55,7 +55,7 @@ static int redisIvykisAttach(redisAsyncContext *ac) {
return REDIS_ERR; return REDIS_ERR;
/* Create container for context and r/w events */ /* Create container for context and r/w events */
e = (redisIvykisEvents*)malloc(sizeof(*e)); e = (redisIvykisEvents*)hi_malloc(sizeof(*e));
e->context = ac; e->context = ac;
/* Register functions to start/stop listening for events */ /* Register functions to start/stop listening for events */

View File

@ -119,7 +119,7 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
return REDIS_ERR; return REDIS_ERR;
/* Create container for context and r/w events */ /* Create container for context and r/w events */
e = (redisLibevEvents*)malloc(sizeof(*e)); e = (redisLibevEvents*)hi_malloc(sizeof(*e));
e->context = ac; e->context = ac;
#if EV_MULTIPLICITY #if EV_MULTIPLICITY
e->loop = loop; e->loop = loop;

View File

@ -152,7 +152,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
return REDIS_ERR; return REDIS_ERR;
/* Create container for context and r/w events */ /* Create container for context and r/w events */
e = (redisLibeventEvents*)calloc(1, sizeof(*e)); e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
e->context = ac; e->context = ac;
/* Register functions to start/stop listening for events */ /* Register functions to start/stop listening for events */

65
alloc.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* 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 <string.h>
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;
}

44
alloc.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* 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 <stdlib.h> /* 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 */

View File

@ -30,6 +30,7 @@
*/ */
#include "fmacros.h" #include "fmacros.h"
#include "alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _MSC_VER #ifndef _MSC_VER
@ -57,7 +58,7 @@ static unsigned int callbackHash(const void *key) {
static void *callbackValDup(void *privdata, const void *src) { static void *callbackValDup(void *privdata, const void *src) {
((void) privdata); ((void) privdata);
redisCallback *dup = malloc(sizeof(*dup)); redisCallback *dup = hi_malloc(sizeof(*dup));
memcpy(dup,src,sizeof(*dup)); memcpy(dup,src,sizeof(*dup));
return dup; return dup;
} }
@ -754,7 +755,7 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) { void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
if (!ac->c.timeout) { 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 && if (tv.tv_sec == ac->c.timeout->tv_sec &&

7
dict.c
View File

@ -34,6 +34,7 @@
*/ */
#include "fmacros.h" #include "fmacros.h"
#include "alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
@ -71,7 +72,7 @@ static void _dictReset(dict *ht) {
/* Create a new hash table */ /* Create a new hash table */
static dict *dictCreate(dictType *type, void *privDataPtr) { static dict *dictCreate(dictType *type, void *privDataPtr) {
dict *ht = malloc(sizeof(*ht)); dict *ht = hi_malloc(sizeof(*ht));
_dictInit(ht,type,privDataPtr); _dictInit(ht,type,privDataPtr);
return ht; return ht;
} }
@ -142,7 +143,7 @@ static int dictAdd(dict *ht, void *key, void *val) {
return DICT_ERR; return DICT_ERR;
/* Allocates the memory and stores key */ /* Allocates the memory and stores key */
entry = malloc(sizeof(*entry)); entry = hi_malloc(sizeof(*entry));
entry->next = ht->table[index]; entry->next = ht->table[index];
ht->table[index] = entry; ht->table[index] = entry;
@ -256,7 +257,7 @@ static dictEntry *dictFind(dict *ht, const void *key) {
} }
static dictIterator *dictGetIterator(dict *ht) { static dictIterator *dictGetIterator(dict *ht) {
dictIterator *iter = malloc(sizeof(*iter)); dictIterator *iter = hi_malloc(sizeof(*iter));
iter->ht = ht; iter->ht = ht;
iter->index = -1; iter->index = -1;

View File

@ -42,6 +42,7 @@ struct timeval; /* forward declaration */
#endif #endif
#include <stdint.h> /* uintXX_t, etc */ #include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for sds */ #include "sds.h" /* for sds */
#include "alloc.h" /* for allocation wrappers */
#define HIREDIS_MAJOR 0 #define HIREDIS_MAJOR 0
#define HIREDIS_MINOR 14 #define HIREDIS_MINOR 14

14
net.c
View File

@ -358,13 +358,13 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
if (c->tcp.host != addr) { if (c->tcp.host != addr) {
free(c->tcp.host); free(c->tcp.host);
c->tcp.host = strdup(addr); c->tcp.host = hi_strdup(addr);
} }
if (timeout) { if (timeout) {
if (c->timeout != timeout) { if (c->timeout != timeout) {
if (c->timeout == NULL) if (c->timeout == NULL)
c->timeout = malloc(sizeof(struct timeval)); c->timeout = hi_malloc(sizeof(struct timeval));
memcpy(c->timeout, timeout, 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; c->tcp.source_addr = NULL;
} else if (c->tcp.source_addr != source_addr) { } else if (c->tcp.source_addr != source_addr) {
free(c->tcp.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); snprintf(_port, 6, "%d", port);
@ -447,7 +447,7 @@ addrretry:
/* For repeat connection */ /* For repeat connection */
free(c->saddr); 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); memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
c->addrlen = 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; c->connection_type = REDIS_CONN_UNIX;
if (c->unix_sock.path != path) if (c->unix_sock.path != path)
c->unix_sock.path = strdup(path); c->unix_sock.path = hi_strdup(path);
if (timeout) { if (timeout) {
if (c->timeout != timeout) { if (c->timeout != timeout) {
if (c->timeout == NULL) if (c->timeout == NULL)
c->timeout = malloc(sizeof(struct timeval)); c->timeout = hi_malloc(sizeof(struct timeval));
memcpy(c->timeout, timeout, 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) if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
return REDIS_ERR; 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); c->addrlen = sizeof(struct sockaddr_un);
sa->sun_family = AF_UNIX; sa->sun_family = AF_UNIX;
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1); strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);

2
ssl.c
View File

@ -151,7 +151,7 @@ static void initOpensslLocks(void) {
return; return;
} }
nlocks = CRYPTO_num_locks(); 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++) { for (ii = 0; ii < nlocks; ii++) {
sslLockInit(ossl_locks + ii); sslLockInit(ossl_locks + ii);
} }