diff --git a/README.md b/README.md index a490085..5f6fe84 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Hiredis-cluster is a fork of Hiredis-vip, with the following improvements: * Using CMake as build system * Code style guide (using clang-format) * Improved testing -* Memory leak corrections +* Memory leak corrections and allocation failure handling ## Features diff --git a/adlist.c b/adlist.c index 607d7fa..c05c9cd 100644 --- a/adlist.c +++ b/adlist.c @@ -27,10 +27,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include "adlist.h" #include "hiutil.h" -#include /* Create a new list. The created list can be freed with * AlFreeList(), but private value of every node need to be freed @@ -40,7 +41,7 @@ hilist *listCreate(void) { struct hilist *list; - if ((list = hi_alloc(sizeof(*list))) == NULL) + if ((list = hi_malloc(sizeof(*list))) == NULL) return NULL; list->head = list->tail = NULL; list->len = 0; @@ -78,7 +79,7 @@ void listRelease(hilist *list) { hilist *listAddNodeHead(hilist *list, void *value) { listNode *node; - if ((node = hi_alloc(sizeof(*node))) == NULL) + if ((node = hi_malloc(sizeof(*node))) == NULL) return NULL; node->value = value; if (list->len == 0) { @@ -103,7 +104,7 @@ hilist *listAddNodeHead(hilist *list, void *value) { hilist *listAddNodeTail(hilist *list, void *value) { listNode *node; - if ((node = hi_alloc(sizeof(*node))) == NULL) + if ((node = hi_malloc(sizeof(*node))) == NULL) return NULL; node->value = value; if (list->len == 0) { @@ -123,7 +124,7 @@ hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after) { listNode *node; - if ((node = hi_alloc(sizeof(*node))) == NULL) + if ((node = hi_malloc(sizeof(*node))) == NULL) return NULL; node->value = value; if (after) { @@ -175,7 +176,7 @@ void listDelNode(hilist *list, listNode *node) { listIter *listGetIterator(hilist *list, int direction) { listIter *iter; - if ((iter = hi_alloc(sizeof(*iter))) == NULL) + if ((iter = hi_malloc(sizeof(*iter))) == NULL) return NULL; if (direction == AL_START_HEAD) iter->next = list->head; @@ -280,6 +281,9 @@ listNode *listSearchKey(hilist *list, void *key) { listNode *node; iter = listGetIterator(list, AL_START_HEAD); + if (iter == NULL) { + return NULL; + } while ((node = listNext(iter)) != NULL) { if (list->match) { if (list->match(node->value, key)) { diff --git a/command.c b/command.c index 74f5540..8853563 100644 --- a/command.c +++ b/command.c @@ -1,5 +1,6 @@ #include #include +#include #include "command.h" #include "hiarray.h" @@ -1099,7 +1100,7 @@ void redis_parse_cmd(struct cmd *r) { kpos = hiarray_push(r->keys); if (kpos == NULL) { - goto enomem; + goto oom; } kpos->start = m; kpos->end = p; @@ -1587,25 +1588,18 @@ void redis_parse_cmd(struct cmd *r) { return; done: - ASSERT(r->type > CMD_UNKNOWN && r->type < CMD_SENTINEL); - r->result = CMD_PARSE_OK; - - return; - -enomem: - - r->result = CMD_PARSE_ENOMEM; - return; error: - r->result = CMD_PARSE_ERROR; errno = EINVAL; if (r->errstr == NULL) { - r->errstr = hi_alloc(100 * sizeof(*r->errstr)); + r->errstr = hi_malloc(100 * sizeof(*r->errstr)); + if (r->errstr == NULL) { + goto oom; + } } len = _scnprintf( @@ -1613,11 +1607,15 @@ void redis_parse_cmd(struct cmd *r) { "Parse command error. Cmd type: %d, state: %d, break position: %d.", r->type, state, (int)(p - r->cmd)); r->errstr[len] = '\0'; + return; + +oom: + r->result = CMD_PARSE_ENOMEM; } struct cmd *command_get() { struct cmd *command; - command = hi_alloc(sizeof(struct cmd)); + command = hi_malloc(sizeof(struct cmd)); if (command == NULL) { return NULL; } @@ -1655,15 +1653,18 @@ void command_destroy(struct cmd *command) { if (command->cmd != NULL) { hi_free(command->cmd); + command->cmd = NULL; } if (command->errstr != NULL) { hi_free(command->errstr); + command->errstr = NULL; } if (command->keys != NULL) { command->keys->nelem = 0; hiarray_destroy(command->keys); + command->keys = NULL; } if (command->frag_seq != NULL) { @@ -1671,9 +1672,7 @@ void command_destroy(struct cmd *command) { command->frag_seq = NULL; } - if (command->reply != NULL) { - freeReplyObject(command->reply); - } + freeReplyObject(command->reply); if (command->sub_commands != NULL) { listRelease(command->sub_commands); diff --git a/dict.c b/dict.c index 92c4b49..5b41240 100644 --- a/dict.c +++ b/dict.c @@ -33,11 +33,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "dict.h" #include #include #include +#include "dict.h" + /* -------------------------- private prototypes ---------------------------- */ static int _dictExpandIfNeeded(dict *ht); @@ -70,7 +71,10 @@ 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)); + if (ht == NULL) + return NULL; + _dictInit(ht, type, privDataPtr); return ht; } @@ -96,7 +100,9 @@ static int dictExpand(dict *ht, unsigned long size) { _dictInit(&n, ht->type, ht->privdata); n.size = realsize; n.sizemask = realsize - 1; - n.table = calloc(realsize, sizeof(dictEntry *)); + n.table = hi_calloc(realsize, sizeof(dictEntry *)); + if (n.table == NULL) + return DICT_ERR; /* Copy all the elements from the old to the new table: * note that if the old hash table is empty ht->size is zero, @@ -124,7 +130,7 @@ static int dictExpand(dict *ht, unsigned long size) { } } assert(ht->used == 0); - free(ht->table); + hi_free(ht->table); /* Remap the new hashtable in the old */ *ht = n; @@ -142,7 +148,10 @@ 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)); + if (entry == NULL) + return DICT_ERR; + entry->next = ht->table[index]; ht->table[index] = entry; @@ -167,13 +176,13 @@ static int _dictClear(dict *ht) { nextHe = he->next; dictFreeEntryKey(ht, he); dictFreeEntryVal(ht, he); - free(he); + hi_free(he); ht->used--; he = nextHe; } } /* Free the table and the allocated cache structure */ - free(ht->table); + hi_free(ht->table); /* Re-initialize the table */ _dictReset(ht); return DICT_OK; /* never fails */ @@ -182,7 +191,7 @@ static int _dictClear(dict *ht) { /* Clear & Release the hash table */ static void dictRelease(dict *ht) { _dictClear(ht); - free(ht); + hi_free(ht); } static dictEntry *dictFind(dict *ht, const void *key) { @@ -202,7 +211,9 @@ static dictEntry *dictFind(dict *ht, const void *key) { } static dictIterator *dictGetIterator(dict *ht) { - dictIterator *iter = malloc(sizeof(*iter)); + dictIterator *iter = hi_malloc(sizeof(*iter)); + if (iter == NULL) + return NULL; iter->ht = ht; iter->index = -1; @@ -231,7 +242,7 @@ static dictEntry *dictNext(dictIterator *iter) { return NULL; } -static void dictReleaseIterator(dictIterator *iter) { free(iter); } +static void dictReleaseIterator(dictIterator *iter) { hi_free(iter); } /* ------------------------- private functions ------------------------------ */ diff --git a/hiarray.c b/hiarray.c index dbc6adb..adac732 100644 --- a/hiarray.c +++ b/hiarray.c @@ -1,3 +1,4 @@ +#include #include #include "hiarray.h" @@ -8,12 +9,12 @@ struct hiarray *hiarray_create(uint32_t n, size_t size) { ASSERT(n != 0 && size != 0); - a = hi_alloc(sizeof(*a)); + a = hi_malloc(sizeof(*a)); if (a == NULL) { return NULL; } - a->elem = hi_alloc(n * size); + a->elem = hi_malloc(n * size); if (a->elem == NULL) { hi_free(a); return NULL; @@ -31,27 +32,11 @@ void hiarray_destroy(struct hiarray *a) { hi_free(a); } -int hiarray_init(struct hiarray *a, uint32_t n, size_t size) { - ASSERT(n != 0 && size != 0); - - a->elem = hi_alloc(n * size); - if (a->elem == NULL) { - return HI_ENOMEM; - } - - a->nelem = 0; - a->size = size; - a->nalloc = n; - - return HI_OK; -} - void hiarray_deinit(struct hiarray *a) { ASSERT(a->nelem == 0); - if (a->elem != NULL) { - hi_free(a->elem); - } + hi_free(a->elem); + a->elem = NULL; } uint32_t hiarray_idx(struct hiarray *a, void *elem) { diff --git a/hiarray.h b/hiarray.h index 81f2695..8460042 100644 --- a/hiarray.h +++ b/hiarray.h @@ -35,7 +35,6 @@ static inline uint32_t hiarray_n(const struct hiarray *a) { return a->nelem; } struct hiarray *hiarray_create(uint32_t n, size_t size); void hiarray_destroy(struct hiarray *a); -int hiarray_init(struct hiarray *a, uint32_t n, size_t size); void hiarray_deinit(struct hiarray *a); uint32_t hiarray_idx(struct hiarray *a, void *elem); diff --git a/hircluster.c b/hircluster.c index fafd557..0c954ed 100644 --- a/hircluster.c +++ b/hircluster.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -283,9 +284,8 @@ static void cluster_node_deinit(cluster_node *node) { node->role = REDIS_ROLE_NULL; node->myself = 0; - if (node->con != NULL) { - redisFree(node->con); - } + redisFree(node->con); + node->con = NULL; if (node->acon != NULL) { redisAsyncFree(node->acon); @@ -331,7 +331,7 @@ static int cluster_slot_init(cluster_slot *slot, cluster_node *node) { static cluster_slot *cluster_slot_create(cluster_node *node) { cluster_slot *slot; - slot = hi_alloc(sizeof(*slot)); + slot = hi_malloc(sizeof(*slot)); if (slot == NULL) { return NULL; } @@ -350,7 +350,10 @@ static cluster_slot *cluster_slot_create(cluster_node *node) { node->slots->free = listClusterSlotDestructor; } - listAddNodeTail(node->slots, slot); + if (listAddNodeTail(node->slots, slot) == NULL) { + cluster_slot_destroy(slot); + return NULL; + } } return slot; @@ -374,7 +377,9 @@ static int cluster_slot_ref_node(cluster_slot *slot, cluster_node *node) { node->slots->free = listClusterSlotDestructor; } - listAddNodeTail(node->slots, slot); + if (listAddNodeTail(node->slots, slot) == NULL) { + return REDIS_ERR; + } slot->node = node; return REDIS_OK; @@ -393,7 +398,7 @@ static copen_slot *cluster_open_slot_create(uint32_t slot_num, int migrate, cluster_node *node) { copen_slot *oslot; - oslot = hi_alloc(sizeof(*oslot)); + oslot = hi_malloc(sizeof(*oslot)); if (oslot == NULL) { return NULL; } @@ -407,6 +412,10 @@ static copen_slot *cluster_open_slot_create(uint32_t slot_num, int migrate, oslot->migrate = migrate; oslot->node = node; oslot->remote_name = sdsdup(remote_name); + if (oslot->remote_name == NULL) { + hi_free(oslot); + return NULL; + } return oslot; } @@ -415,12 +424,8 @@ static void cluster_open_slot_destroy(copen_slot *oslot) { oslot->slot_num = 0; oslot->migrate = 0; oslot->node = NULL; - - if (oslot->remote_name != NULL) { - sdsfree(oslot->remote_name); - oslot->remote_name = NULL; - } - + sdsfree(oslot->remote_name); + oslot->remote_name = NULL; hi_free(oslot); } @@ -453,10 +458,8 @@ static int authenticate(redisClusterContext *cc, redisContext *c) { return REDIS_OK; error: - if (reply != NULL) { - freeReplyObject(reply); - reply = NULL; - } + freeReplyObject(reply); + return REDIS_ERR; } @@ -493,10 +496,9 @@ static cluster_node *node_get_with_slots(redisClusterContext *cc, goto error; } - node = hi_alloc(sizeof(cluster_node)); + node = hi_malloc(sizeof(cluster_node)); if (node == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } cluster_node_init(node); @@ -504,31 +506,40 @@ static cluster_node *node_get_with_slots(redisClusterContext *cc, if (role == REDIS_ROLE_MASTER) { node->slots = listCreate(); if (node->slots == NULL) { - hi_free(node); - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "slots for node listCreate error"); - goto error; + goto oom; } node->slots->free = listClusterSlotDestructor; } - node->name = NULL; node->addr = sdsnewlen(host_elem->str, host_elem->len); + if (node->addr == NULL) { + goto oom; + } node->addr = sdscatfmt(node->addr, ":%i", port_elem->integer); - + if (node->addr == NULL) { + goto oom; + } node->host = sdsnewlen(host_elem->str, host_elem->len); + if (node->host == NULL) { + goto oom; + } + node->name = NULL; node->port = (int)port_elem->integer; node->role = role; return node; -error: +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: if (node != NULL) { + sdsfree(node->addr); + sdsfree(node->host); hi_free(node); } - return NULL; } @@ -540,25 +551,22 @@ static cluster_node *node_get_with_nodes(redisClusterContext *cc, uint8_t role) { char *p = NULL; char *port = NULL; - cluster_node *node; + cluster_node *node = NULL; if (info_count < 8) { return NULL; } - node = hi_alloc(sizeof(cluster_node)); + node = hi_malloc(sizeof(cluster_node)); if (node == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return NULL; + goto oom; } cluster_node_init(node); if (role == REDIS_ROLE_MASTER) { node->slots = listCreate(); if (node->slots == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "slots for node listCreate error"); - goto error; + goto oom; } node->slots->free = listClusterSlotDestructor; @@ -577,6 +585,9 @@ static cluster_node *node_get_with_nodes(redisClusterContext *cc, } node->host = sdsnewlen(node_infos[1], p - node_infos[1]); + if (node->host == NULL) { + goto oom; + } p++; // remove found separator character // Strip away cport if given by redis @@ -594,15 +605,18 @@ static cluster_node *node_get_with_nodes(redisClusterContext *cc, return node; -error: +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough - if (node->slots) { - listRelease(node->slots); - } - if (node->host) { +error: + if (node) { + if (node->slots) { + listRelease(node->slots); + } sdsfree(node->host); + hi_free(node); } - hi_free(node); return NULL; } @@ -618,6 +632,10 @@ static void cluster_nodes_swap_ctx(dict *nodes_f, dict *nodes_t) { } di = dictGetIterator(nodes_t); + if (di == NULL) { + return; + } + while ((de_t = dictNext(di)) != NULL) { node_t = dictGetEntryVal(de_t); if (node_t == NULL) { @@ -646,7 +664,6 @@ static void cluster_nodes_swap_ctx(dict *nodes_f, dict *nodes_t) { node_f->acon->data = node_f; } } - dictReleaseIterator(di); } @@ -671,16 +688,21 @@ static int cluster_master_slave_mapping_with_name(redisClusterContext *cc, if (*nodes == NULL) { *nodes = dictCreate(&clusterNodesRefDictType, NULL); + if (*nodes == NULL) { + goto oom; + } } di = dictFind(*nodes, master_name); if (di == NULL) { - ret = - dictAdd(*nodes, sdsnewlen(master_name, sdslen(master_name)), node); + sds key = sdsnewlen(master_name, sdslen(master_name)); + if (key == NULL) { + goto oom; + } + ret = dictAdd(*nodes, key, node); if (ret != DICT_OK) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "the address already exists in the nodes"); - return REDIS_ERR; + sdsfree(key); + goto oom; } } else { @@ -700,8 +722,7 @@ static int cluster_master_slave_mapping_with_name(redisClusterContext *cc, if (node->slaves == NULL) { node->slaves = listCreate(); if (node->slaves == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; + goto oom; } node->slaves->free = listClusterNodeDestructor; @@ -711,34 +732,43 @@ static int cluster_master_slave_mapping_with_name(redisClusterContext *cc, node_old->slaves->free = NULL; while (listLength(node_old->slaves) > 0) { lnode = listFirst(node_old->slaves); - listAddNodeHead(node->slaves, lnode->value); + if (listAddNodeHead(node->slaves, lnode->value) == NULL) { + goto oom; + } listDelNode(node_old->slaves, lnode); } listRelease(node_old->slaves); node_old->slaves = NULL; } - listAddNodeHead(node->slaves, node_old); - + if (listAddNodeHead(node->slaves, node_old) == NULL) { + goto oom; + } dictSetHashVal(*nodes, di, node); + } else if (node->role == REDIS_ROLE_SLAVE) { if (node_old->slaves == NULL) { node_old->slaves = listCreate(); if (node_old->slaves == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; + goto oom; } node_old->slaves->free = listClusterNodeDestructor; } + if (listAddNodeTail(node_old->slaves, node) == NULL) { + goto oom; + } - listAddNodeTail(node_old->slaves, node); } else { NOT_REACHED(); } } return REDIS_OK; + +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; } /** @@ -755,7 +785,6 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, redisReply *elem_nodes; redisReply *elem_ip, *elem_port; cluster_node *master = NULL, *slave; - sds address; uint32_t i, idx; if (reply == NULL) { @@ -764,8 +793,7 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, nodes = dictCreate(&clusterNodesDictType, NULL); if (nodes == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "out of memory"); - goto error; + goto oom; } if (reply->type != REDIS_REPLY_ARRAY || reply->elements <= 0) { @@ -786,9 +814,7 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, slot = cluster_slot_create(NULL); if (slot == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Slot create failed: out of memory."); - goto error; + goto oom; } // one slots region @@ -848,52 +874,54 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, // this is master. if (idx == 2) { - address = sdsnewlen(elem_ip->str, elem_ip->len); + sds address = sdsnewlen(elem_ip->str, elem_ip->len); + if (address == NULL) { + goto oom; + } address = sdscatfmt(address, ":%i", elem_port->integer); + if (address == NULL) { + goto oom; + } den = dictFind(nodes, address); - // master already exits, break to the next slots region. + sdsfree(address); + // master already exists, break to the next slots region. if (den != NULL) { - sdsfree(address); master = dictGetEntryVal(den); ret = cluster_slot_ref_node(slot, master); if (ret != REDIS_OK) { - __redisClusterSetError( - cc, REDIS_ERR_OOM, - "Slot ref node failed: out of memory."); - goto error; + goto oom; } slot = NULL; break; } - sdsfree(address); master = node_get_with_slots(cc, elem_ip, elem_port, REDIS_ROLE_MASTER); if (master == NULL) { goto error; } - ret = dictAdd(nodes, - sdsnewlen(master->addr, sdslen(master->addr)), - master); + sds key = sdsnewlen(master->addr, sdslen(master->addr)); + if (key == NULL) { + cluster_node_deinit(master); + hi_free(master); + goto oom; + } + + ret = dictAdd(nodes, key, master); if (ret != DICT_OK) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "The address already exists in the nodes"); + sdsfree(key); cluster_node_deinit(master); hi_free(master); - goto error; + goto oom; } ret = cluster_slot_ref_node(slot, master); if (ret != REDIS_OK) { - __redisClusterSetError( - cc, REDIS_ERR_OOM, - "Slot ref node failed: out of memory."); - goto error; + goto oom; } slot = NULL; @@ -907,16 +935,19 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, if (master->slaves == NULL) { master->slaves = listCreate(); if (master->slaves == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Out of memory"); cluster_node_deinit(slave); - goto error; + hi_free(slave); + goto oom; } master->slaves->free = listClusterNodeDestructor; } - listAddNodeTail(master->slaves, slave); + if (listAddNodeTail(master->slaves, slave) == NULL) { + cluster_node_deinit(slave); + hi_free(slave); + goto oom; + } } } } @@ -924,16 +955,17 @@ dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, return nodes; -error: +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: if (nodes != NULL) { dictRelease(nodes); } - if (slot != NULL) { cluster_slot_destroy(slot); } - return NULL; } @@ -959,8 +991,7 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, nodes = dictCreate(&clusterNodesDictType, NULL); if (nodes == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "out of memory"); - goto error; + goto oom; } start = str; @@ -974,8 +1005,11 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, len = line_end - line_start; part = sdssplitlen(line_start, len + 1, " ", 1, &count_part); + if (part == NULL) { + goto oom; + } - if (part == NULL || count_part < 8) { + if (count_part < 8) { __redisClusterSetError(cc, REDIS_ERR_OTHER, "split cluster nodes error"); goto error; @@ -1018,13 +1052,20 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, goto error; } - ret = dictAdd(nodes, - sdsnewlen(master->addr, sdslen(master->addr)), - master); + sds key = sdsnewlen(master->addr, sdslen(master->addr)); + if (key == NULL) { + cluster_node_deinit(master); + hi_free(master); + goto oom; + } + + ret = dictAdd(nodes, key, master); if (ret != DICT_OK) { + // Key already exists, but possibly an OOM error __redisClusterSetError( cc, REDIS_ERR_OTHER, "The address already exists in the nodes"); + sdsfree(key); cluster_node_deinit(master); hi_free(master); goto error; @@ -1046,13 +1087,11 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, for (k = 8; k < count_part; k++) { slot_start_end = sdssplitlen(part[k], sdslen(part[k]), "-", 1, &count_slot_start_end); - if (slot_start_end == NULL) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "split slot start end error(NULL)"); - goto error; - } else if (count_slot_start_end == 1) { + goto oom; + } + + if (count_slot_start_end == 1) { slot_start = hi_atoi(slot_start_end[0], sdslen(slot_start_end[0])); slot_end = slot_start; @@ -1095,22 +1134,15 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, master->migrating = hiarray_create(1, sizeof(oslot)); if (master->migrating == NULL) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "create migrating array error"); cluster_open_slot_destroy(oslot); - goto error; + goto oom; } } oslot_elem = hiarray_push(master->migrating); if (oslot_elem == NULL) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "Push migrating array error: out of " - "memory"); cluster_open_slot_destroy(oslot); - goto error; + goto oom; } *oslot_elem = oslot; @@ -1130,22 +1162,15 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, master->importing = hiarray_create(1, sizeof(oslot)); if (master->importing == NULL) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "create migrating array error"); cluster_open_slot_destroy(oslot); - goto error; + goto oom; } } oslot_elem = hiarray_push(master->importing); if (oslot_elem == NULL) { - __redisClusterSetError( - cc, REDIS_ERR_OTHER, - "push migrating array error: out of " - "memory"); cluster_open_slot_destroy(oslot); - goto error; + goto oom; } *oslot_elem = oslot; @@ -1168,9 +1193,7 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, slot = cluster_slot_create(master); if (slot == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Out of memory"); - goto error; + goto oom; } slot->start = (uint32_t)slot_start; @@ -1219,28 +1242,19 @@ dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, return nodes; -error: - - if (part != NULL) { - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - } - - if (slot_start_end != NULL) { - sdsfreesplitres(slot_start_end, count_slot_start_end); - count_slot_start_end = 0; - slot_start_end = NULL; - } +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: + sdsfreesplitres(part, count_part); + sdsfreesplitres(slot_start_end, count_slot_start_end); if (nodes != NULL) { dictRelease(nodes); } - if (nodes_name != NULL) { dictRelease(nodes_name); } - return NULL; } @@ -1278,10 +1292,9 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, } if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Init redis context error(return NULL)"); - goto error; - } else if (c->err) { + goto oom; + } + if (c->err) { __redisClusterSetError(cc, c->err, c->errstr); goto error; } @@ -1365,22 +1378,18 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, slots = hiarray_create(dictSize(nodes), sizeof(cluster_slot *)); if (slots == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Slots array create failed: out of memory"); - goto error; + goto oom; } dit = dictGetIterator(nodes); if (dit == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Dict get iterator failed: out of memory"); - goto error; + goto oom; } while ((den = dictNext(dit))) { master = dictGetEntryVal(den); if (master->role != REDIS_ROLE_MASTER) { - __redisClusterSetError(cc, REDIS_ERR_OOM, + __redisClusterSetError(cc, REDIS_ERR_OTHER, "Node role must be master"); goto error; } @@ -1391,9 +1400,7 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, lit = listGetIterator(master->slots, AL_START_HEAD); if (lit == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, - "List get iterator failed: out of memory"); - goto error; + goto oom; } while ((lnode = listNext(lit))) { @@ -1405,6 +1412,9 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, } slot_elem = hiarray_push(slots); + if (slot_elem == NULL) { + goto oom; + } *slot_elem = slot; } @@ -1428,6 +1438,7 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, } } + // Move all hiredis contexts in cc->nodes to nodes cluster_nodes_swap_ctx(cc->nodes, nodes); if (cc->nodes != NULL) { dictRelease(cc->nodes); @@ -1447,22 +1458,17 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, freeReplyObject(reply); - if (c != NULL) { - redisFree(c); - } + redisFree(c); return REDIS_OK; -error: - - if (dit != NULL) { - dictReleaseIterator(dit); - } - - if (lit != NULL) { - listReleaseIterator(lit); - } +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: + dictReleaseIterator(dit); + listReleaseIterator(lit); if (slots != NULL) { if (slots == cc->slots) { cc->slots = NULL; @@ -1471,24 +1477,14 @@ static int cluster_update_route_by_addr(redisClusterContext *cc, const char *ip, slots->nelem = 0; hiarray_destroy(slots); } - if (nodes != NULL) { if (nodes == cc->nodes) { cc->nodes = NULL; } - dictRelease(nodes); } - - if (reply != NULL) { - freeReplyObject(reply); - reply = NULL; - } - - if (c != NULL) { - redisFree(c); - } - + freeReplyObject(reply); + redisFree(c); return REDIS_ERR; } @@ -1512,6 +1508,11 @@ int cluster_update_route(redisClusterContext *cc) { } it = dictGetIterator(cc->nodes); + if (it == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + while ((de = dictNext(it)) != NULL) { node = dictGetEntryVal(de); if (node == NULL || node->host == NULL || node->port < 0) { @@ -1543,9 +1544,9 @@ int cluster_update_route(redisClusterContext *cc) { #ifdef DEBUG static void print_cluster_node_list(redisClusterContext *cc) { - dictIterator *di = NULL; + dictIterator *dit = NULL; dictEntry *de; - listIter *it; + listIter *lit; listNode *ln; cluster_node *master, *slave; hilist *slaves; @@ -1554,11 +1555,15 @@ static void print_cluster_node_list(redisClusterContext *cc) { return; } - di = dictGetIterator(cc->nodes); + dit = dictGetIterator(cc->nodes); + if (dit == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return; + } printf("name\taddress\trole\tslaves\n"); - while ((de = dictNext(di)) != NULL) { + while ((de = dictNext(dit)) != NULL) { master = dictGetEntryVal(de); printf("%s\t%s\t%d\t%s\n", master->name, master->addr, master->role, @@ -1569,17 +1574,22 @@ static void print_cluster_node_list(redisClusterContext *cc) { continue; } - it = listGetIterator(slaves, AL_START_HEAD); - while ((ln = listNext(it)) != NULL) { + lit = listGetIterator(slaves, AL_START_HEAD); + if (lit == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return; + } + while ((ln = listNext(lit)) != NULL) { slave = listNodeValue(ln); printf("%s\t%s\t%d\t%s\n", slave->name, slave->addr, slave->role, slave->slaves ? "hava" : "null"); } - listReleaseIterator(it); + listReleaseIterator(lit); printf("\n"); } + dictReleaseIterator(dit); } #endif /* DEBUG */ @@ -1598,7 +1608,7 @@ int test_cluster_update_route(redisClusterContext *cc) { redisClusterContext *redisClusterContextInit(void) { redisClusterContext *cc; - cc = calloc(1, sizeof(redisClusterContext)); + cc = hi_calloc(1, sizeof(redisClusterContext)); if (cc == NULL) return NULL; @@ -1635,11 +1645,13 @@ void redisClusterFree(redisClusterContext *cc) { return; if (cc->connect_timeout) { - free(cc->connect_timeout); + hi_free(cc->connect_timeout); + cc->connect_timeout = NULL; } if (cc->command_timeout) { - free(cc->command_timeout); + hi_free(cc->command_timeout); + cc->command_timeout = NULL; } memset(cc->table, 0, REDIS_CLUSTER_SLOTS * sizeof(cluster_node *)); @@ -1658,7 +1670,7 @@ void redisClusterFree(redisClusterContext *cc) { listRelease(cc->requests); } - free(cc); + hi_free(cc); } /* Connect to a Redis cluster. On error the field error in the returned @@ -1727,7 +1739,10 @@ redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, } if (cc->connect_timeout == NULL) { - cc->connect_timeout = malloc(sizeof(struct timeval)); + cc->connect_timeout = hi_malloc(sizeof(struct timeval)); + if (cc->connect_timeout == NULL) { + return NULL; + } } memcpy(cc->connect_timeout, &tv, sizeof(struct timeval)); @@ -1755,10 +1770,9 @@ redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags) { int redisClusterSetOptionAddNode(redisClusterContext *cc, const char *addr) { dictEntry *node_entry; - cluster_node *node; - sds ip; - int port; - sds addr_sds = NULL; + cluster_node *node = NULL; + int port, ret; + sds ip = NULL; if (cc == NULL) { return REDIS_ERR; @@ -1767,11 +1781,14 @@ int redisClusterSetOptionAddNode(redisClusterContext *cc, const char *addr) { if (cc->nodes == NULL) { cc->nodes = dictCreate(&clusterNodesDictType, NULL); if (cc->nodes == NULL) { - return REDIS_ERR; + goto oom; } } - addr_sds = sdsnew(addr); + sds addr_sds = sdsnew(addr); + if (addr_sds == NULL) { + goto oom; + } node_entry = dictFind(cc->nodes, addr_sds); sdsfree(addr_sds); if (node_entry == NULL) { @@ -1791,8 +1808,11 @@ int redisClusterSetOptionAddNode(redisClusterContext *cc, const char *addr) { "server address is incorrect, address part missing."); return REDIS_ERR; } - ip = sdsnewlen(addr, p - addr); + ip = sdsnewlen(addr, p - addr); + if (ip == NULL) { + goto oom; + } p++; // remove separator character if (strlen(p) <= 0) { @@ -1809,32 +1829,42 @@ int redisClusterSetOptionAddNode(redisClusterContext *cc, const char *addr) { return REDIS_ERR; } - node = hi_alloc(sizeof(cluster_node)); + node = hi_malloc(sizeof(cluster_node)); if (node == NULL) { - sdsfree(ip); - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "alloc cluster node error"); - return REDIS_ERR; + goto oom; } cluster_node_init(node); node->addr = sdsnew(addr); if (node->addr == NULL) { - sdsfree(ip); - hi_free(node); - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "new node address error"); - return REDIS_ERR; + goto oom; } node->host = ip; node->port = port; - dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), node); + sds key = sdsnewlen(node->addr, sdslen(node->addr)); + if (key == NULL) { + goto oom; + } + ret = dictAdd(cc->nodes, key, node); + if (ret != DICT_OK) { + sdsfree(key); + goto oom; + } } return REDIS_OK; + +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + sdsfree(ip); + if (node != NULL) { + sdsfree(node->addr); + hi_free(node); + } + return REDIS_ERR; } int redisClusterSetOptionAddNodes(redisClusterContext *cc, const char *addrs) { @@ -1849,7 +1879,12 @@ int redisClusterSetOptionAddNodes(redisClusterContext *cc, const char *addrs) { address = sdssplitlen(addrs, strlen(addrs), CLUSTER_ADDRESS_SEPARATOR, strlen(CLUSTER_ADDRESS_SEPARATOR), &address_count); - if (address == NULL || address_count <= 0) { + if (address == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + + if (address_count <= 0) { __redisClusterSetError(cc, REDIS_ERR_OTHER, "servers address is error(correct is like: " "127.0.0.1:1234,127.0.0.2:5678)"); @@ -1953,7 +1988,11 @@ int redisClusterSetOptionConnectTimeout(redisClusterContext *cc, } if (cc->connect_timeout == NULL) { - cc->connect_timeout = malloc(sizeof(struct timeval)); + cc->connect_timeout = hi_malloc(sizeof(struct timeval)); + if (cc->connect_timeout == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } } memcpy(cc->connect_timeout, &tv, sizeof(struct timeval)); @@ -1964,12 +2003,17 @@ int redisClusterSetOptionConnectTimeout(redisClusterContext *cc, int redisClusterSetOptionTimeout(redisClusterContext *cc, const struct timeval tv) { + dictIterator *di = NULL; + if (cc == NULL) { return REDIS_ERR; } if (cc->command_timeout == NULL) { - cc->command_timeout = malloc(sizeof(struct timeval)); + cc->command_timeout = hi_malloc(sizeof(struct timeval)); + if (cc->command_timeout == NULL) { + goto oom; + } memcpy(cc->command_timeout, &tv, sizeof(struct timeval)); } else if (cc->command_timeout->tv_sec != tv.tv_sec || cc->command_timeout->tv_usec != tv.tv_usec) { @@ -1977,10 +2021,12 @@ int redisClusterSetOptionTimeout(redisClusterContext *cc, if (cc->nodes && dictSize(cc->nodes) > 0) { dictEntry *de; - dictIterator *di; cluster_node *node; di = dictGetIterator(cc->nodes); + if (di == NULL) { + goto oom; + } while ((de = dictNext(di)) != NULL) { node = dictGetEntryVal(de); @@ -1995,6 +2041,10 @@ int redisClusterSetOptionTimeout(redisClusterContext *cc, listNode *ln; li = listGetIterator(node->slaves, AL_START_HEAD); + if (li == NULL) { + goto oom; + } + while ((ln = listNext(li)) != NULL) { slave = listNodeValue(ln); if (slave->con && slave->con->flags & REDIS_CONNECTED && @@ -2002,16 +2052,19 @@ int redisClusterSetOptionTimeout(redisClusterContext *cc, redisSetTimeout(slave->con, tv); } } - listReleaseIterator(li); } } - dictReleaseIterator(di); } } return REDIS_OK; + +oom: + dictReleaseIterator(di); + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; } int redisClusterSetOptionMaxRedirect(redisClusterContext *cc, @@ -2065,11 +2118,11 @@ redisContext *ctx_get_by_node(redisClusterContext *cc, cluster_node *node) { } } #endif - authenticate(cc, c); // err and errstr handled in function - if (cc->command_timeout && c->err == 0) { redisSetTimeout(c, *cc->command_timeout); } + + authenticate(cc, c); // err and errstr handled in function } return c; @@ -2086,7 +2139,18 @@ redisContext *ctx_get_by_node(redisClusterContext *cc, cluster_node *node) { c = redisConnect(node->host, node->port); } - if (cc->command_timeout && c != NULL && c->err == 0) { + if (c == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return NULL; + } + + if (c->err) { + __redisClusterSetError(cc, c->err, c->errstr); + redisFree(c); + return NULL; + } + + if (cc->command_timeout) { redisSetTimeout(c, *cc->command_timeout); } @@ -2135,6 +2199,11 @@ static cluster_node *node_get_which_connected(redisClusterContext *cc) { } di = dictGetIterator(cc->nodes); + if (di == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return NULL; + } + while ((de = dictNext(di)) != NULL) { node = dictGetEntryVal(de); if (node == NULL) { @@ -2155,14 +2224,13 @@ static cluster_node *node_get_which_connected(redisClusterContext *cc) { dictReleaseIterator(di); return node; - } else if (reply != NULL) { + } else { freeReplyObject(reply); reply = NULL; } } dictReleaseIterator(di); - return NULL; } @@ -2189,6 +2257,9 @@ static char *cluster_config_get(redisClusterContext *cc, } c = ctx_get_by_node(cc, node); + if (c == NULL) { + goto error; + } reply = redisCommand(c, "config get %s", config_name); if (reply == NULL) { @@ -2236,17 +2307,13 @@ static char *cluster_config_get(redisClusterContext *cc, *config_value_len = sub_reply->len; sub_reply->str = NULL; - if (reply != NULL) { - freeReplyObject(reply); - } + freeReplyObject(reply); return config_value; error: - if (reply != NULL) { - freeReplyObject(reply); - } + freeReplyObject(reply); return NULL; } @@ -2275,7 +2342,6 @@ static int __redisClusterAppendCommand(redisClusterContext *cc, c = ctx_get_by_node(cc, node); if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); return REDIS_ERR; } else if (c->err) { __redisClusterSetError(cc, c->err, c->errstr); @@ -2311,7 +2377,6 @@ static int __redisClusterGetReply(redisClusterContext *cc, int slot_num, c = ctx_get_by_node(cc, node); if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); return REDIS_ERR; } else if (c->err) { if (cc->need_update_route == 0) { @@ -2340,7 +2405,7 @@ static int __redisClusterGetReply(redisClusterContext *cc, int slot_num, static cluster_node *node_get_by_ask_error_reply(redisClusterContext *cc, redisReply *reply) { sds *part = NULL, *ip_port = NULL; - int part_len = 0, ip_port_len; + int part_len = 0, ip_port_len = 0, ret; dictEntry *de; cluster_node *node = NULL; @@ -2354,18 +2419,22 @@ static cluster_node *node_get_by_ask_error_reply(redisClusterContext *cc, } part = sdssplitlen(reply->str, reply->len, " ", 1, &part_len); + if (part == NULL) { + goto oom; + } - if (part != NULL && part_len == 3) { + if (part_len == 3) { ip_port = sdssplitlen(part[2], sdslen(part[2]), ":", 1, &ip_port_len); + if (ip_port == NULL) { + goto oom; + } - if (ip_port != NULL && ip_port_len == 2) { + if (ip_port_len == 2) { de = dictFind(cc->nodes, part[2]); if (de == NULL) { - node = hi_alloc(sizeof(cluster_node)); + node = hi_malloc(sizeof(cluster_node)); if (node == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - - goto done; + goto oom; } cluster_node_init(node); @@ -2374,14 +2443,21 @@ static cluster_node *node_get_by_ask_error_reply(redisClusterContext *cc, node->port = hi_atoi(ip_port[1], sdslen(ip_port[1])); node->role = REDIS_ROLE_MASTER; - dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), - node); + sds key = sdsnewlen(node->addr, sdslen(node->addr)); + if (key == NULL) { + goto oom; + } + + ret = dictAdd(cc->nodes, key, node); + if (ret != DICT_OK) { + sdsfree(key); + goto oom; + } part[1] = NULL; ip_port[0] = NULL; } else { node = de->val; - goto done; } } else { @@ -2399,18 +2475,15 @@ static cluster_node *node_get_by_ask_error_reply(redisClusterContext *cc, } done: - - if (part != NULL) { - sdsfreesplitres(part, part_len); - part = NULL; - } - - if (ip_port != NULL) { - sdsfreesplitres(ip_port, ip_port_len); - ip_port = NULL; - } - + sdsfreesplitres(part, part_len); + sdsfreesplitres(ip_port, ip_port_len); return node; + +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + sdsfreesplitres(part, part_len); + sdsfreesplitres(ip_port, ip_port_len); + return NULL; } static void *redis_cluster_command_execute(redisClusterContext *cc, @@ -2431,7 +2504,6 @@ static void *redis_cluster_command_execute(redisClusterContext *cc, c = ctx_get_by_node(cc, node); if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); return NULL; } else if (c->err) { node = node_get_which_connected(cc); @@ -2450,8 +2522,6 @@ static void *redis_cluster_command_execute(redisClusterContext *cc, c = ctx_get_by_node(cc, node); if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "ctx get by node error"); return NULL; } else if (c->err) { __redisClusterSetError(cc, c->err, c->errstr); @@ -2510,8 +2580,6 @@ static void *redis_cluster_command_execute(redisClusterContext *cc, c = ctx_get_by_node(cc, node); if (c == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "ctx get by node error"); return NULL; } else if (c->err) { __redisClusterSetError(cc, c->err, c->errstr); @@ -2567,16 +2635,15 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, key_count = hiarray_n(command->keys); - sub_commands = hi_zalloc(REDIS_CLUSTER_SLOTS * sizeof(*sub_commands)); + sub_commands = hi_malloc(REDIS_CLUSTER_SLOTS * sizeof(*sub_commands)); if (sub_commands == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto done; + goto oom; } + memset(sub_commands, 0, REDIS_CLUSTER_SLOTS * sizeof(*sub_commands)); - command->frag_seq = hi_alloc(key_count * sizeof(*command->frag_seq)); + command->frag_seq = hi_malloc(key_count * sizeof(*command->frag_seq)); if (command->frag_seq == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto done; + goto oom; } // Fill sub_command with key, slot and command length (clen, only keylength) @@ -2594,9 +2661,7 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, if (sub_commands[slot_num] == NULL) { sub_commands[slot_num] = command_get(); if (sub_commands[slot_num] == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } } @@ -2606,9 +2671,7 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, sub_kp = hiarray_push(sub_command->keys); if (sub_kp == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } sub_kp->start = kp->start; @@ -2665,12 +2728,12 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, sub_command->clen += 13 + num_str_len; sub_command->cmd = - hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + hi_malloc(sub_command->clen * sizeof(*sub_command->cmd)); if (sub_command->cmd == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } + memset(sub_command->cmd, 0, + sub_command->clen * sizeof(*sub_command->cmd)); sub_command->cmd[idx++] = '*'; memcpy(sub_command->cmd + idx, num_str, num_str_len); @@ -2707,12 +2770,12 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, sub_command->clen += 12 + num_str_len; sub_command->cmd = - hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + hi_malloc(sub_command->clen * sizeof(*sub_command->cmd)); if (sub_command->cmd == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } + memset(sub_command->cmd, 0, + sub_command->clen * sizeof(*sub_command->cmd)); sub_command->cmd[idx++] = '*'; memcpy(sub_command->cmd + idx, num_str, num_str_len); @@ -2749,12 +2812,12 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, sub_command->clen += 15 + num_str_len; sub_command->cmd = - hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + hi_malloc(sub_command->clen * sizeof(*sub_command->cmd)); if (sub_command->cmd == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } + memset(sub_command->cmd, 0, + sub_command->clen * sizeof(*sub_command->cmd)); sub_command->cmd[idx++] = '*'; memcpy(sub_command->cmd + idx, num_str, num_str_len); @@ -2793,12 +2856,12 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, sub_command->clen += 13 + num_str_len; sub_command->cmd = - hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + hi_malloc(sub_command->clen * sizeof(*sub_command->cmd)); if (sub_command->cmd == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - slot_num = -1; - goto done; + goto oom; } + memset(sub_command->cmd, 0, + sub_command->clen * sizeof(*sub_command->cmd)); sub_command->cmd[idx++] = '*'; memcpy(sub_command->cmd + idx, num_str, num_str_len); @@ -2825,20 +2888,15 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, NOT_REACHED(); } - // printf("len : %d\n", sub_command->clen); - // print_string_with_length_fix_CRLF(sub_command->cmd, - // sub_command->clen); - sub_command->type = command->type; - listAddNodeTail(commands, sub_command); + if (listAddNodeTail(commands, sub_command) == NULL) { + goto oom; + } } done: - - if (sub_commands != NULL) { - hi_free(sub_commands); - } + hi_free(sub_commands); if (slot_num >= 0 && commands != NULL && listLength(commands) == 1) { listNode *list_node = listFirst(commands); @@ -2850,8 +2908,12 @@ static int command_pre_fragment(redisClusterContext *cc, struct cmd *command, command->slot_num = slot_num; } - return slot_num; + +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + hi_free(sub_commands); + return -1; // failing slot_num } static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, @@ -2859,10 +2921,13 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, struct cmd *sub_command; listNode *list_node; listIter *list_iter; - redisReply *reply, *sub_reply; + redisReply *reply = NULL, *sub_reply; long long count = 0; list_iter = listGetIterator(commands, AL_START_HEAD); + if (list_iter == NULL) { + goto oom; + } while ((list_node = listNext(list_iter)) != NULL) { sub_command = list_node->value; reply = sub_command->reply; @@ -2886,7 +2951,6 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, listReleaseIterator(list_iter); return NULL; } - count += reply->integer; } else if (command->type == CMD_REQ_REDIS_EXISTS) { if (reply->type != REDIS_REPLY_INTEGER) { @@ -2894,7 +2958,6 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, listReleaseIterator(list_iter); return NULL; } - count += reply->integer; } else if (command->type == CMD_REQ_REDIS_MSET) { if (reply->type != REDIS_REPLY_STATUS || reply->len != 2 || @@ -2910,10 +2973,8 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, listReleaseIterator(list_iter); reply = hi_calloc(1, sizeof(*reply)); - if (reply == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return NULL; + goto oom; } if (command->type == CMD_REQ_REDIS_MGET) { @@ -2927,9 +2988,7 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, reply->elements = key_count; reply->element = hi_calloc(key_count, sizeof(*reply)); if (reply->element == NULL) { - freeReplyObject(reply); - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return NULL; + goto oom; } for (i = key_count - 1; i >= 0; i--) { /* for each key */ @@ -2964,11 +3023,9 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, } else if (command->type == CMD_REQ_REDIS_MSET) { reply->type = REDIS_REPLY_STATUS; uint32_t str_len = strlen(REDIS_STATUS_OK); - reply->str = hi_alloc((str_len + 1) * sizeof(char *)); + reply->str = hi_malloc((str_len + 1) * sizeof(char *)); if (reply->str == NULL) { - freeReplyObject(reply); - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return NULL; + goto oom; } reply->len = str_len; @@ -2979,6 +3036,11 @@ static void *command_post_fragment(redisClusterContext *cc, struct cmd *command, } return reply; + +oom: + freeReplyObject(reply); + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return NULL; } /* @@ -3002,8 +3064,7 @@ static int command_format_by_slot(redisClusterContext *cc, struct cmd *command, redis_parse_cmd(command); if (command->result == CMD_PARSE_ENOMEM) { - __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, - "Parse command error: out of memory"); + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); goto done; } else if (command->result != CMD_PARSE_OK) { __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, command->errstr); @@ -3061,8 +3122,7 @@ void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, command = command_get(); if (command == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - return NULL; + goto oom; } command->cmd = cmd; @@ -3070,8 +3130,7 @@ void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, commands = listCreate(); if (commands == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } commands->free = listCommandFree; @@ -3094,6 +3153,10 @@ void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, ASSERT(listLength(commands) != 1); list_iter = listGetIterator(commands, AL_START_HEAD); + if (list_iter == NULL) { + goto oom; + } + while ((list_node = listNext(list_iter)) != NULL) { sub_command = list_node->value; @@ -3118,31 +3181,24 @@ void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, listRelease(commands); } - if (list_iter != NULL) { - listReleaseIterator(list_iter); - } - + listReleaseIterator(list_iter); cc->retry_count = 0; - return reply; -error: +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: if (command != NULL) { command->cmd = NULL; command_destroy(command); } - if (commands != NULL) { listRelease(commands); } - - if (list_iter != NULL) { - listReleaseIterator(list_iter); - } - + listReleaseIterator(list_iter); cc->retry_count = 0; - return NULL; } @@ -3168,7 +3224,7 @@ void *redisClustervCommand(redisClusterContext *cc, const char *format, reply = redisClusterFormattedCommand(cc, cmd, len); - free(cmd); + hi_free(cmd); return reply; } @@ -3198,7 +3254,7 @@ void *redisClusterCommandArgv(redisClusterContext *cc, int argc, reply = redisClusterFormattedCommand(cc, cmd, len); - free(cmd); + hi_free(cmd); return reply; } @@ -3214,17 +3270,14 @@ int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, if (cc->requests == NULL) { cc->requests = listCreate(); if (cc->requests == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } - cc->requests->free = listCommandFree; } command = command_get(); if (command == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } command->cmd = cmd; @@ -3232,8 +3285,7 @@ int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, commands = listCreate(); if (commands == NULL) { - __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } commands->free = listCommandFree; @@ -3247,30 +3299,30 @@ int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, goto error; } - // all keys belong to one slot + // Append command(s) if (listLength(commands) == 0) { - if (__redisClusterAppendCommand(cc, command) == REDIS_OK) { - goto done; - } else { + // All keys belong to one slot + if (__redisClusterAppendCommand(cc, command) != REDIS_OK) { goto error; } - } + } else { + // Keys belongs to different slots + ASSERT(listLength(commands) != 1); - ASSERT(listLength(commands) != 1); + list_iter = listGetIterator(commands, AL_START_HEAD); + if (list_iter == NULL) { + goto oom; + } - list_iter = listGetIterator(commands, AL_START_HEAD); - while ((list_node = listNext(list_iter)) != NULL) { - sub_command = list_node->value; + while ((list_node = listNext(list_iter)) != NULL) { + sub_command = list_node->value; - if (__redisClusterAppendCommand(cc, sub_command) == REDIS_OK) { - continue; - } else { - goto error; + if (__redisClusterAppendCommand(cc, sub_command) != REDIS_OK) { + goto error; + } } } -done: - if (command->cmd != NULL) { command->cmd = NULL; } else { @@ -3282,36 +3334,35 @@ int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, command->sub_commands = commands; } else { listRelease(commands); + commands = NULL; } } - if (list_iter != NULL) { - listReleaseIterator(list_iter); - } - - listAddNodeTail(cc->requests, command); + listReleaseIterator(list_iter); + list_iter = NULL; + if (listAddNodeTail(cc->requests, command) == NULL) { + goto oom; + } return REDIS_OK; -error: +oom: + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: if (command != NULL) { command->cmd = NULL; command_destroy(command); } - if (commands != NULL) { listRelease(commands); } - - if (list_iter != NULL) { - listReleaseIterator(list_iter); - } + listReleaseIterator(list_iter); /* Attention: mybe here we must pop the sub_commands that had append to the nodes. But now we do not handle it. */ - return REDIS_ERR; } @@ -3332,7 +3383,7 @@ int redisClustervAppendCommand(redisClusterContext *cc, const char *format, ret = redisClusterAppendFormattedCommand(cc, cmd, len); - free(cmd); + hi_free(cmd); return ret; } @@ -3368,7 +3419,7 @@ int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, ret = redisClusterAppendFormattedCommand(cc, cmd, len); - free(cmd); + hi_free(cmd); return ret; } @@ -3385,6 +3436,11 @@ static int redisClusterSendAll(redisClusterContext *cc) { } di = dictGetIterator(cc->nodes); + if (di == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + while ((de = dictNext(di)) != NULL) { node = dictGetEntryVal(de); if (node == NULL) { @@ -3430,7 +3486,13 @@ static int redisClusterClearAll(redisClusterContext *cc) { if (cc->nodes == NULL) { return REDIS_ERR; } + di = dictGetIterator(cc->nodes); + if (di == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + while ((de = dictNext(di)) != NULL) { node = dictGetEntryVal(de); if (node == NULL) { @@ -3502,6 +3564,11 @@ int redisClusterGetReply(redisClusterContext *cc, void **reply) { ASSERT(listLength(commands) != 1); list_iter = listGetIterator(commands, AL_START_HEAD); + if (list_iter == NULL) { + __redisClusterSetError(cc, REDIS_ERR_OOM, "Out of memory"); + goto error; + } + while ((list_sub_command = listNext(list_iter)) != NULL) { sub_command = list_sub_command->value; if (sub_command == NULL) { @@ -3534,10 +3601,7 @@ int redisClusterGetReply(redisClusterContext *cc, void **reply) { error: - if (list_iter != NULL) { - listReleaseIterator(list_iter); - } - + listReleaseIterator(list_iter); listDelNode(cc->requests, list_command); return REDIS_ERR; } @@ -3611,7 +3675,7 @@ redisClusterAsyncInitialize(redisClusterContext *cc) { return NULL; } - acc = hi_alloc(sizeof(redisClusterAsyncContext)); + acc = hi_malloc(sizeof(redisClusterAsyncContext)); if (acc == NULL) return NULL; @@ -3636,7 +3700,7 @@ redisClusterAsyncInitialize(redisClusterContext *cc) { static cluster_async_data *cluster_async_data_get(void) { cluster_async_data *cad; - cad = hi_alloc(sizeof(cluster_async_data)); + cad = hi_malloc(sizeof(cluster_async_data)); if (cad == NULL) { return NULL; } @@ -3655,12 +3719,9 @@ static void cluster_async_data_free(cluster_async_data *cad) { return; } - if (cad->command != NULL) { - command_destroy(cad->command); - } + command_destroy(cad->command); hi_free(cad); - cad = NULL; } static void unlinkAsyncContextAndNode(void *data) { @@ -3931,7 +3992,8 @@ static void redisClusterAsyncCallback(redisAsyncContext *ac, void *r, cluster_timeout = hi_atoi(cluster_timeout_str, cluster_timeout_str_len); - free(cluster_timeout_str); + hi_free(cluster_timeout_str); + if (cluster_timeout <= 0) { __redisClusterAsyncSetError( acc, REDIS_ERR_OTHER, @@ -4032,9 +4094,7 @@ static void redisClusterAsyncCallback(redisAsyncContext *ac, void *r, memset(acc->errstr, '\0', strlen(acc->errstr)); } - if (cad != NULL) { - cluster_async_data_free(cad); - } + cluster_async_data_free(cad); return; @@ -4050,9 +4110,7 @@ static void redisClusterAsyncCallback(redisAsyncContext *ac, void *r, error: - if (cad != NULL) { - cluster_async_data_free(cad); - } + cluster_async_data_free(cad); } int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, @@ -4086,22 +4144,19 @@ int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, command = command_get(); if (command == NULL) { - __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } - command->cmd = malloc(len * sizeof(*command->cmd)); + command->cmd = hi_malloc(len * sizeof(*command->cmd)); if (command->cmd == NULL) { - __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } memcpy(command->cmd, cmd, len); command->clen = len; commands = listCreate(); if (commands == NULL) { - __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } commands->free = listCommandFree; @@ -4146,8 +4201,7 @@ int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, cad = cluster_async_data_get(); if (cad == NULL) { - __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); - goto error; + goto oom; } cad->acc = acc; @@ -4167,16 +4221,15 @@ int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, return REDIS_OK; -error: - - if (command != NULL) { - command_destroy(command); - } +oom: + __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); + // passthrough +error: + command_destroy(command); if (commands != NULL) { listRelease(commands); } - return REDIS_ERR; } @@ -4203,7 +4256,7 @@ int redisClustervAsyncCommand(redisClusterAsyncContext *acc, ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); - free(cmd); + hi_free(cmd); return ret; } @@ -4237,7 +4290,7 @@ int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); - free(cmd); + hi_free(cmd); return ret; } @@ -4264,6 +4317,10 @@ void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc) { } di = dictGetIterator(nodes); + if (di == NULL) { + __redisClusterAsyncSetError(acc, REDIS_ERR_OOM, "Out of memory"); + return; + } while ((de = dictNext(di)) != NULL) { node = dictGetEntryVal(de); diff --git a/hiutil.c b/hiutil.c index f8e9908..fae6f6f 100644 --- a/hiutil.c +++ b/hiutil.c @@ -1,23 +1,25 @@ -#include "win32.h" #include #include +#include #include #include #include #include +#include #ifndef WIN32 #include #include #include #endif -#include "hiutil.h" -#include #ifdef HI_HAVE_BACKTRACE #include #endif +#include "hiutil.h" +#include "win32.h" + #ifndef WIN32 int hi_set_blocking(int sd) { int flags; @@ -228,56 +230,6 @@ int _uint_len(uint32_t num) { return n; } -void *_hi_alloc(size_t size, const char *name, int line) { - void *p; - - ASSERT(size != 0); - - p = malloc(size); - - if (name == NULL && line == 1) { - } - - return p; -} - -void *_hi_zalloc(size_t size, const char *name, int line) { - void *p; - - p = _hi_alloc(size, name, line); - if (p != NULL) { - memset(p, 0, size); - } - - return p; -} - -void *_hi_calloc(size_t nmemb, size_t size, const char *name, int line) { - return _hi_zalloc(nmemb * size, name, line); -} - -void *_hi_realloc(void *ptr, size_t size, const char *name, int line) { - void *p; - - ASSERT(size != 0); - - p = realloc(ptr, size); - - if (name == NULL && line == 1) { - } - - return p; -} - -void _hi_free(void *ptr, const char *name, int line) { - ASSERT(ptr != NULL); - - if (name == NULL && line == 1) { - } - - free(ptr); -} - void hi_stacktrace(int skip_count) { if (skip_count > 0) { } @@ -299,7 +251,7 @@ void hi_stacktrace(int skip_count) { printf("[%d] %s\n", j, symbols[i]); } - free(symbols); + hi_free(symbols); #endif } diff --git a/hiutil.h b/hiutil.h index a7e8b0f..a05b590 100644 --- a/hiutil.h +++ b/hiutil.h @@ -12,7 +12,6 @@ typedef SSIZE_T ssize_t; #define HI_OK 0 #define HI_ERROR -1 #define HI_EAGAIN -2 -#define HI_ENOMEM -3 typedef int rstatus_t; /* return type */ @@ -153,35 +152,6 @@ int hi_valid_port(int n); int _uint_len(uint32_t num); -/* - * Memory allocation and free wrappers. - * - * These wrappers enables us to loosely detect double free, dangling - * pointer access and zero-byte alloc. - */ -#define hi_alloc(_s) _hi_alloc((size_t)(_s), __FILE__, __LINE__) - -#define hi_zalloc(_s) _hi_zalloc((size_t)(_s), __FILE__, __LINE__) - -#define hi_calloc(_n, _s) \ - _hi_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) - -#define hi_realloc(_p, _s) _hi_realloc(_p, (size_t)(_s), __FILE__, __LINE__) - -#define hi_free(_p) \ - do { \ - _hi_free(_p, __FILE__, __LINE__); \ - (_p) = NULL; \ - } while (0) - -void *_hi_alloc(size_t size, const char *name, int line); -void *_hi_zalloc(size_t size, const char *name, int line); -void *_hi_calloc(size_t nmemb, size_t size, const char *name, int line); -void *_hi_realloc(void *ptr, size_t size, const char *name, int line); -void _hi_free(void *ptr, const char *name, int line); - -#define hi_strndup(_s, _n) strndup((char *)(_s), (size_t)(_n)); - #ifndef WIN32 /* * Wrappers to send or receive n byte message on a blocking diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 28a23a4..683f1b5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -78,6 +78,11 @@ if(ENABLE_IPV6_TESTS) set_tests_properties(ct_connection_ipv6 PROPERTIES LABELS "CT") endif() +add_executable(ct_out_of_memory_handling ct_out_of_memory_handling.c) +target_link_libraries(ct_out_of_memory_handling hiredis_cluster hiredis ${SSL_LIBRARY}) +add_test(NAME ct_out_of_memory_handling COMMAND "$") +set_tests_properties(ct_out_of_memory_handling PROPERTIES LABELS "CT") + if(ENABLE_SSL) # Executable: tls add_executable(example_tls main_tls.c) diff --git a/tests/ct_out_of_memory_handling.c b/tests/ct_out_of_memory_handling.c new file mode 100644 index 0000000..0a996f3 --- /dev/null +++ b/tests/ct_out_of_memory_handling.c @@ -0,0 +1,156 @@ +#include "hircluster.h" +#include "test_utils.h" +#include +#include +#include +#include + +#define CLUSTER_NODE "127.0.0.1:7000" + +int successfulAllocations = 0; + +// A configurable OOM failing malloc() +static void *hi_malloc_fail(size_t size) { + if (successfulAllocations > 0) { + --successfulAllocations; + return malloc(size); + } + return NULL; +} + +// A configurable OOM failing calloc() +static void *hi_calloc_fail(size_t nmemb, size_t size) { + if (successfulAllocations > 0) { + --successfulAllocations; + return calloc(nmemb, size); + } + return NULL; +} + +// A configurable OOM failing realloc() +static void *hi_realloc_fail(void *ptr, size_t size) { + if (successfulAllocations > 0) { + --successfulAllocations; + return realloc(ptr, size); + } + return NULL; +} + +void prepare_allocation_test(redisClusterContext *cc, + int _successfulAllocations) { + successfulAllocations = _successfulAllocations; + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); +} + +// Test of allocation handling +// The testcase will trigger allocation failures during API calls. +// It will start by triggering an allocation fault, and the next iteration +// will start with an successfull allocation and then a failing one, +// next iteration 2 successful and one failing allocation, and so on.. +void test_cluster_communication() { + int result; + hiredisAllocFuncs ha = { + .mallocFn = hi_malloc_fail, + .callocFn = hi_calloc_fail, + .reallocFn = hi_realloc_fail, + .strdupFn = strdup, + .freeFn = free, + }; + // Override allocators + hiredisSetAllocators(&ha); + + // Context init + redisClusterContext *cc; + { + successfulAllocations = 0; + cc = redisClusterContextInit(); + assert(cc == NULL); + + successfulAllocations = 1; + cc = redisClusterContextInit(); + assert(cc); + } + + // Add nodes + { + for (int i = 0; i < 9; ++i) { + prepare_allocation_test(cc, i); + result = redisClusterSetOptionAddNodes(cc, CLUSTER_NODE); + assert(result == REDIS_ERR); + ASSERT_STR_EQ(cc->errstr, "Out of memory"); + } + + prepare_allocation_test(cc, 9); + result = redisClusterSetOptionAddNodes(cc, CLUSTER_NODE); + assert(result == REDIS_OK); + } + + // Set timeout + { + struct timeval timeout = {0, 500000}; + + prepare_allocation_test(cc, 0); + result = redisClusterSetOptionConnectTimeout(cc, timeout); + assert(result == REDIS_ERR); + ASSERT_STR_EQ(cc->errstr, "Out of memory"); + + prepare_allocation_test(cc, 1); + result = redisClusterSetOptionConnectTimeout(cc, timeout); + assert(result == REDIS_OK); + } + + // Connect + { + for (int i = 0; i < 133; ++i) { + prepare_allocation_test(cc, i); + result = redisClusterConnect2(cc); + assert(result == REDIS_ERR); + } + + prepare_allocation_test(cc, 133); + result = redisClusterConnect2(cc); + assert(result == REDIS_OK); + } + + // Command + { + redisReply *reply; + + for (int i = 0; i < 36; ++i) { + prepare_allocation_test(cc, 0 + i); + reply = (redisReply *)redisClusterCommand(cc, "SET key value"); + assert(reply == NULL); + ASSERT_STR_EQ(cc->errstr, "Out of memory"); + } + + prepare_allocation_test(cc, 36); + reply = (redisReply *)redisClusterCommand(cc, "SET key value"); + CHECK_REPLY_OK(cc, reply); + freeReplyObject(reply); + } + + // Append command + { + for (int i = 0; i < 33; ++i) { + prepare_allocation_test(cc, 0 + i); + result = redisClusterAppendCommand(cc, "SET foo one"); + assert(result == REDIS_ERR); + ASSERT_STR_EQ(cc->errstr, "Out of memory"); + } + + prepare_allocation_test(cc, 33); + result = redisClusterAppendCommand(cc, "SET foo one"); + assert(result == REDIS_OK); + } + + redisClusterFree(cc); + hiredisResetAllocators(); +} + +int main() { + + test_cluster_communication(); + + return 0; +} diff --git a/tests/test_utils.h b/tests/test_utils.h index bbb48ff..654d1c2 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -57,4 +57,10 @@ _ctx->errstr); \ } +#define ASSERT_STR_EQ(_s1, _s2) \ + { assert(strcmp(_s1, _s2) == 0); } + +#define ASSERT_STR_STARTS_WITH(_s1, _s2) \ + { assert(strncmp(_s1, _s2, strlen(_s2)) == 0); } + #endif diff --git a/win32.h b/win32.h index 7f7aea8..1d24450 100644 --- a/win32.h +++ b/win32.h @@ -8,10 +8,6 @@ #define inline __inline #endif -#ifndef strdup -#define strdup _strdup -#endif - #ifndef strcasecmp #define strcasecmp _stricmp #endif