Minimalistic C client for Redis >= 1.2

Related tags

Database hiredis
Overview

Build Status

This Readme reflects the latest changed in the master branch. See v1.0.0 for the Readme and documentation for the latest release (API/ABI history).

HIREDIS

Hiredis is a minimalistic C client library for the Redis database.

It is minimalistic because it just adds minimal support for the protocol, but at the same time it uses a high level printf-alike API in order to make it much higher level than otherwise suggested by its minimal code base and the lack of explicit bindings for every Redis command.

Apart from supporting sending commands and receiving replies, it comes with a reply parser that is decoupled from the I/O layer. It is a stream parser designed for easy reusability, which can for instance be used in higher level language bindings for efficient reply parsing.

Hiredis only supports the binary-safe Redis protocol, so you can use it with any Redis version >= 1.2.0.

The library comes with multiple APIs. There is the synchronous API, the asynchronous API and the reply parsing API.

Upgrading to 1.0.0

Version 1.0.0 marks the first stable release of Hiredis. It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. It also bundles the updated sds library, to sync up with upstream and Redis. For code changes see the Changelog.

Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling.

IMPORTANT: Breaking changes from 0.14.1 -> 1.0.0

  • redisContext has two additional members (free_privdata, and privctx).
  • redisOptions.timeout has been renamed to redisOptions.connect_timeout, and we've added redisOptions.command_timeout.
  • redisReplyObjectFunctions.createArray now takes size_t instead of int for its length parameter.

IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x

Bulk and multi-bulk lengths less than -1 or greater than LLONG_MAX are now protocol errors. This is consistent with the RESP specification. On 32-bit platforms, the upper bound is lowered to SIZE_MAX.

Change redisReply.len to size_t, as it denotes the the size of a string

User code should compare this to size_t values as well. If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.

Upgrading from <0.9.0

Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing code using hiredis should not be a big pain. The key thing to keep in mind when upgrading is that hiredis >= 0.9.0 uses a redisContext* to keep state, in contrast to the stateless 0.0.1 that only has a file descriptor to work with.

Synchronous API

To consume the synchronous API, there are only a few function calls that need to be introduced:

redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);

Connecting

The function redisConnect is used to create a so-called redisContext. The context is where Hiredis holds state for a connection. The redisContext struct has an integer err field that is non-zero when the connection is in an error state. The field errstr will contain a string with a description of the error. More information on errors can be found in the Errors section. After trying to connect to Redis using redisConnect you should check the err field to see if establishing the connection was successful:

redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
    if (c) {
        printf("Error: %s\n", c->errstr);
        // handle error
    } else {
        printf("Can't allocate redis context\n");
    }
}

Note: A redisContext is not thread-safe.

Sending commands

There are several ways to issue commands to Redis. The first that will be introduced is redisCommand. This function takes a format similar to printf. In the simplest form, it is used like this:

reply = redisCommand(context, "SET foo bar");

The specifier %s interpolates a string in the command, and uses strlen to determine the length of the string:

reply = redisCommand(context, "SET foo %s", value);

When you need to pass binary safe strings in a command, the %b specifier can be used. Together with a pointer to the string, it requires a size_t length argument of the string:

reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);

Internally, Hiredis splits the command in different arguments and will convert it to the protocol used to communicate with Redis. One or more spaces separates arguments, so you can use the specifiers anywhere in an argument:

reply = redisCommand(context, "SET key:%s %s", myid, value);

Using replies

The return value of redisCommand holds a reply when the command was successfully executed. When an error occurs, the return value is NULL and the err field in the context will be set (see section on Errors). Once an error is returned the context cannot be reused and you should set up a new connection.

The standard replies that redisCommand are of the type redisReply. The type field in the redisReply should be used to test what kind of reply was received:

RESP2

  • REDIS_REPLY_STATUS:

    • The command replied with a status reply. The status string can be accessed using reply->str. The length of this string can be accessed using reply->len.
  • REDIS_REPLY_ERROR:

    • The command replied with an error. The error string can be accessed identical to REDIS_REPLY_STATUS.
  • REDIS_REPLY_INTEGER:

    • The command replied with an integer. The integer value can be accessed using the reply->integer field of type long long.
  • REDIS_REPLY_NIL:

    • The command replied with a nil object. There is no data to access.
  • REDIS_REPLY_STRING:

    • A bulk (string) reply. The value of the reply can be accessed using reply->str. The length of this string can be accessed using reply->len.
  • REDIS_REPLY_ARRAY:

    • A multi bulk reply. The number of elements in the multi bulk reply is stored in reply->elements. Every element in the multi bulk reply is a redisReply object as well and can be accessed via reply->element[..index..]. Redis may reply with nested arrays but this is fully supported.

RESP3

Hiredis also supports every new RESP3 data type which are as follows. For more information about the protocol see the RESP3 specification.

  • REDIS_REPLY_DOUBLE:

    • The command replied with a double-precision floating point number. The value is stored as a string in the str member, and can be converted with strtod or similar.
  • REDIS_REPLY_BOOL:

    • A boolean true/false reply. The value is stored in the integer member and will be either 0 or 1.
  • REDIS_REPLY_MAP:

    • An array with the added invariant that there will always be an even number of elements. The MAP is functionally equivelant to REDIS_REPLY_ARRAY except for the previously mentioned invariant.
  • REDIS_REPLY_SET:

    • An array response where each entry is unique. Like the MAP type, the data is identical to an array response except there are no duplicate values.
  • REDIS_REPLY_PUSH:

    • An array that can be generated spontaneously by Redis. This array response will always contain at least two subelements. The first contains the type of PUSH message (e.g. message, or invalidate), and the second being a sub-array with the PUSH payload itself.
  • REDIS_REPLY_ATTR:

    • An array structurally identical to a MAP but intended as meta-data about a reply. As of Redis 6.0.6 this reply type is not used in Redis
  • REDIS_REPLY_BIGNUM:

    • A string representing an arbitrarily large signed or unsigned integer value. The number will be encoded as a string in the str member of redisReply.
  • REDIS_REPLY_VERB:

    • A verbatim string, intended to be presented to the user without modification. The string payload is stored in the str memeber, and type data is stored in the vtype member (e.g. txt for raw text or md for markdown).

Replies should be freed using the freeReplyObject() function. Note that this function will take care of freeing sub-reply objects contained in arrays and nested arrays, so there is no need for the user to free the sub replies (it is actually harmful and will corrupt the memory).

Important: the current version of hiredis (1.0.0) frees replies when the asynchronous API is used. This means you should not call freeReplyObject when you use this API. The reply is cleaned up by hiredis after the callback returns. We may introduce a flag to make this configurable in future versions of the library.

Cleaning up

To disconnect and free the context the following function can be used:

void redisFree(redisContext *c);

This function immediately closes the socket and then frees the allocations done in creating the context.

Sending commands (cont'd)

Together with redisCommand, the function redisCommandArgv can be used to issue commands. It has the following prototype:

void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

It takes the number of arguments argc, an array of strings argv and the lengths of the arguments argvlen. For convenience, argvlen may be set to NULL and the function will use strlen(3) on every argument to determine its length. Obviously, when any of the arguments need to be binary safe, the entire array of lengths argvlen should be provided.

The return value has the same semantic as redisCommand.

Pipelining

To explain how Hiredis supports pipelining in a blocking connection, there needs to be understanding of the internal execution flow.

When any of the functions in the redisCommand family is called, Hiredis first formats the command according to the Redis protocol. The formatted command is then put in the output buffer of the context. This output buffer is dynamic, so it can hold any number of commands. After the command is put in the output buffer, redisGetReply is called. This function has the following two execution paths:

  1. The input buffer is non-empty:
    • Try to parse a single reply from the input buffer and return it
    • If no reply could be parsed, continue at 2
  2. The input buffer is empty:
    • Write the entire output buffer to the socket
    • Read from the socket until a single reply could be parsed

The function redisGetReply is exported as part of the Hiredis API and can be used when a reply is expected on the socket. To pipeline commands, the only things that needs to be done is filling up the output buffer. For this cause, two commands can be used that are identical to the redisCommand family, apart from not returning a reply:

void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

After calling either function one or more times, redisGetReply can be used to receive the subsequent replies. The return value for this function is either REDIS_OK or REDIS_ERR, where the latter means an error occurred while reading a reply. Just as with the other commands, the err field in the context can be used to find out what the cause of this error is.

The following examples shows a simple pipeline (resulting in only a single call to write(2) and a single call to read(2)):

redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,(void *)&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,(void *)&reply); // reply for GET
freeReplyObject(reply);

This API can also be used to implement a blocking subscriber:

reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
    // consume message
    freeReplyObject(reply);
}

Errors

When a function call is not successful, depending on the function either NULL or REDIS_ERR is returned. The err field inside the context will be non-zero and set to one of the following constants:

  • REDIS_ERR_IO: There was an I/O error while creating the connection, trying to write to the socket or read from the socket. If you included errno.h in your application, you can use the global errno variable to find out what is wrong.

  • REDIS_ERR_EOF: The server closed the connection which resulted in an empty read.

  • REDIS_ERR_PROTOCOL: There was an error while parsing the protocol.

  • REDIS_ERR_OTHER: Any other error. Currently, it is only used when a specified hostname to connect to cannot be resolved.

In every case, the errstr field in the context will be set to hold a string representation of the error.

Asynchronous API

Hiredis comes with an asynchronous API that works easily with any event library. Examples are bundled that show using Hiredis with libev and libevent.

Connecting

The function redisAsyncConnect can be used to establish a non-blocking connection to Redis. It returns a pointer to the newly created redisAsyncContext struct. The err field should be checked after creation to see if there were errors creating the connection. Because the connection that will be created is non-blocking, the kernel is not able to instantly return if the specified host and port is able to accept a connection.

Note: A redisAsyncContext is not thread-safe.

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
    printf("Error: %s\n", c->errstr);
    // handle error
}

The asynchronous context can hold a disconnect callback function that is called when the connection is disconnected (either because of an error or per user request). This function should have the following prototype:

void(const redisAsyncContext *c, int status);

On a disconnect, the status argument is set to REDIS_OK when disconnection was initiated by the user, or REDIS_ERR when the disconnection was caused by an error. When it is REDIS_ERR, the err field in the context can be accessed to find out the cause of the error.

The context object is always freed after the disconnect callback fired. When a reconnect is needed, the disconnect callback is a good point to do so.

Setting the disconnect callback can only be done once per context. For subsequent calls it will return REDIS_ERR. The function to set the disconnect callback has the following prototype:

int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

ac->data may be used to pass user data to this callback, the same can be done for redisConnectCallback.

Sending commands and their callbacks

In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. Therefore, unlike the synchronous API, there is only a single way to send commands. Because commands are sent to Redis asynchronously, issuing a command requires a callback function that is called when the reply is received. Reply callbacks should have the following prototype:

void(redisAsyncContext *c, void *reply, void *privdata);

The privdata argument can be used to curry arbitrary data to the callback from the point where the command is initially queued for execution.

The functions that can be used to issue commands in an asynchronous context are:

int redisAsyncCommand(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  const char *format, ...);
int redisAsyncCommandArgv(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  int argc, const char **argv, const size_t *argvlen);

Both functions work like their blocking counterparts. The return value is REDIS_OK when the command was successfully added to the output buffer and REDIS_ERR otherwise. Example: when the connection is being disconnected per user-request, no new commands may be added to the output buffer and REDIS_ERR is returned on calls to the redisAsyncCommand family.

If the reply for a command with a NULL callback is read, it is immediately freed. When the callback for a command is non-NULL, the memory is freed immediately following the callback: the reply is only valid for the duration of the callback.

All pending callbacks are called with a NULL reply when the context encountered an error.

Disconnecting

An asynchronous connection can be terminated using:

void redisAsyncDisconnect(redisAsyncContext *ac);

When this function is called, the connection is not immediately terminated. Instead, new commands are no longer accepted and the connection is only terminated when all pending commands have been written to the socket, their respective replies have been read and their respective callbacks have been executed. After this, the disconnection callback is executed with the REDIS_OK status and the context object is freed.

Hooking it up to event library X

There are a few hooks that need to be set on the context object after it is created. See the adapters/ directory for bindings to libev and libevent.

Reply parsing API

Hiredis comes with a reply parsing API that makes it easy for writing higher level language bindings.

The reply parsing API consists of the following functions:

redisReader *redisReaderCreate(void);
void redisReaderFree(redisReader *reader);
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
int redisReaderGetReply(redisReader *reader, void **reply);

The same set of functions are used internally by hiredis when creating a normal Redis context, the above API just exposes it to the user for a direct usage.

Usage

The function redisReaderCreate creates a redisReader structure that holds a buffer with unparsed data and state for the protocol parser.

Incoming data -- most likely from a socket -- can be placed in the internal buffer of the redisReader using redisReaderFeed. This function will make a copy of the buffer pointed to by buf for len bytes. This data is parsed when redisReaderGetReply is called. This function returns an integer status and a reply object (as described above) via void **reply. The returned status can be either REDIS_OK or REDIS_ERR, where the latter means something went wrong (either a protocol error, or an out of memory error).

The parser limits the level of nesting for multi bulk payloads to 7. If the multi bulk nesting level is higher than this, the parser returns an error.

Customizing replies

The function redisReaderGetReply creates redisReply and makes the function argument reply point to the created redisReply variable. For instance, if the response of type REDIS_REPLY_STATUS then the str field of redisReply will hold the status as a vanilla C string. However, the functions that are responsible for creating instances of the redisReply can be customized by setting the fn field on the redisReader struct. This should be done immediately after creating the redisReader.

For example, hiredis-rb uses customized reply object functions to create Ruby objects.

Reader max buffer

Both when using the Reader API directly or when using it indirectly via a normal Redis context, the redisReader structure uses a buffer in order to accumulate data from the server. Usually this buffer is destroyed when it is empty and is larger than 16 KiB in order to avoid wasting memory in unused buffers

However when working with very big payloads destroying the buffer may slow down performances considerably, so it is possible to modify the max size of an idle buffer changing the value of the maxbuf field of the reader structure to the desired value. The special value of 0 means that there is no maximum value for an idle buffer, so the buffer will never get freed.

For instance if you have a normal Redis context you can set the maximum idle buffer to zero (unlimited) just with:

context->reader->maxbuf = 0;

This should be done only in order to maximize performances when working with large payloads. The context should be set back to REDIS_READER_MAX_BUF again as soon as possible in order to prevent allocation of useless memory.

Reader max array elements

By default the hiredis reply parser sets the maximum number of multi-bulk elements to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies with more than this many elements you can set the value higher or to zero, meaning unlimited with:

context->reader->maxelements = 0;

SSL/TLS Support

Building

SSL/TLS support is not built by default and requires an explicit flag:

make USE_SSL=1

This requires OpenSSL development package (e.g. including header files to be available.

When enabled, SSL/TLS support is built into extra libhiredis_ssl.a and libhiredis_ssl.so static/dynamic libraries. This leaves the original libraries unaffected so no additional dependencies are introduced.

Using it

First, you'll need to make sure you include the SSL header file:

#include "hiredis.h"
#include "hiredis_ssl.h"

You will also need to link against libhiredis_ssl, in addition to libhiredis and add -lssl -lcrypto to satisfy its dependencies.

Hiredis implements SSL/TLS on top of its normal redisContext or redisAsyncContext, so you will need to establish a connection first and then initiate an SSL/TLS handshake.

Hiredis OpenSSL Wrappers

Before Hiredis can negotiate an SSL/TLS connection, it is necessary to initialize OpenSSL and create a context. You can do that in two ways:

  1. Work directly with the OpenSSL API to initialize the library's global context and create SSL_CTX * and SSL * contexts. With an SSL * object you can call redisInitiateSSL().
  2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a redisSSLContext object to hold configuration and use redisInitiateSSLWithContext() to initiate the SSL/TLS handshake.
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
 * many contexts.
 */
redisSSLContext *ssl_context;

/* An error variable to indicate what went wrong, if the context fails to
 * initialize.
 */
redisSSLContextError ssl_error;

/* Initialize global OpenSSL state.
 *
 * You should call this only once when your app initializes, and only if
 * you don't explicitly or implicitly initialize OpenSSL it elsewhere.
 */
redisInitOpenSSL();

/* Create SSL context */
ssl_context = redisCreateSSLContext(
    "cacertbundle.crt",     /* File name of trusted CA/ca bundle file, optional */
    "/path/to/certs",       /* Path of trusted certificates, optional */
    "client_cert.pem",      /* File name of client certificate file, optional */
    "client_key.pem",       /* File name of client private key, optional */
    "redis.mydomain.com",   /* Server name to request (SNI), optional */
    &ssl_error);

if(ssl_context == NULL || ssl_error != 0) {
    /* Handle error and abort... */
    /* e.g. 
    printf("SSL error: %s\n", 
        (ssl_error != 0) ? 
            redisSSLContextGetError(ssl_error) : "Unknown error");
    // Abort
    */
}

/* Create Redis context and establish connection */
c = redisConnect("localhost", 6443);
if (c == NULL || c->err) {
    /* Handle error and abort... */
}

/* Negotiate SSL/TLS */
if (redisInitiateSSLWithContext(c, ssl_context) != REDIS_OK) {
    /* Handle error, in c->err / c->errstr */
}

RESP3 PUSH replies

Redis 6.0 introduced PUSH replies with the reply-type >. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.

Default behavior

Hiredis installs handlers on redisContext and redisAsyncContext by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to RESP3.

Custom PUSH handler prototypes

The callback prototypes differ between redisContext and redisAsyncContext.

redisContext

void my_push_handler(void *privdata, void *reply) {
    /* Handle the reply */

    /* Note: We need to free the reply in our custom handler for
             blocking contexts.  This lets us keep the reply if
             we want. */
    freeReplyObject(reply);
}

redisAsyncContext

void my_async_push_handler(redisAsyncContext *ac, void *reply) {
    /* Handle the reply */

    /* Note:  Because async hiredis always frees replies, you should
              not call freeReplyObject in an async push callback. */
}

Installing a custom handler

There are two ways to set your own PUSH handlers.

  1. Set push_cb or async_push_cb in the redisOptions struct and connect with redisConnectWithOptions or redisAsyncConnectWithOptions.

    redisOptions = {0};
    REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
    options->push_cb = my_push_handler;
    redisContext *context = redisConnectWithOptions(&options);
  2. Call redisSetPushCallback or redisAsyncSetPushCallback on a connected context.

    redisContext *context = redisConnect("127.0.0.1", 6379);
    redisSetPushCallback(context, my_push_handler);

    Note redisSetPushCallback and redisAsyncSetPushCallback both return any currently configured handler, making it easy to override and then return to the old value.

Specifying no handler

If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.

  1. Set the REDIS_OPT_NO_PUSH_AUTOFREE flag in redisOptions and leave the callback function pointer NULL.

    redisOptions = {0};
    REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
    options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
    redisContext *context = redisConnectWithOptions(&options);
  2. Call redisSetPushCallback with NULL once connected.

    redisContext *context = redisConnect("127.0.0.1", 6379);
    redisSetPushCallback(context, NULL);

    Note: With no handler configured, calls to redisCommand may generate more than one reply, so this strategy is only applicable when there's some kind of blockingredisGetReply() loop (e.g. MONITOR or SUBSCRIBE workloads).

Allocator injection

Hiredis uses a pass-thru structure of function pointers defined in alloc.h that contain the currently configured allocation and deallocation functions. By default they just point to libc (malloc, calloc, realloc, etc).

Overriding

One can override the allocators like so:

hiredisAllocFuncs myfuncs = {
    .mallocFn = my_malloc,
    .callocFn = my_calloc,
    .reallocFn = my_realloc,
    .strdupFn = my_strdup,
    .freeFn = my_free,
};

// Override allocators (function returns current allocators if needed)
hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);

To reset the allocators to their default libc function simply call:

hiredisResetAllocators();

AUTHORS

Salvatore Sanfilippo (antirez at gmail),
Pieter Noordhuis (pcnoordhuis at gmail)
Michael Grunder (michael dot grunder at gmail)

Hiredis is released under the BSD license.

Comments
  • Add timeout option to requests

    Add timeout option to requests

    While connectWithTimeout will guard against the use case of a slow initial handshake, there's nothing that guards against delays with requests on current connections. The example case here is if Redis spikes to 100% CPU utilization for any number of reasons (out of sockets, memory issues, etc) then anything left holding a connection will suffer without the ability to timeout. I have run into this a couple times now and would like to see it solved. I am happy to implement, but looking for at least a thumbs up on interest before I start.

    opened by abedra 38
  • difficulty building on aix - cannot locate struct timeval

    difficulty building on aix - cannot locate struct timeval

    receive the following message:

    In file included from hiredis/hiredis.c:39: hiredis/hiredis.h:175: warning: 'struct timeval' declared inside parameter list hiredis/hiredis.h:175: warning: its scope is only this definition or declaration, which is probably not what you want

    I am using gcc 4.4 on aix 5.3.

    opened by slestak 24
  • hiredis hangs on redisBufferRead

    hiredis hangs on redisBufferRead

    We use hiredis to connect to redis server in block mode. Our application runs in RHEL 4 32 bit. It works fine and after some time while trying to do an operation, it hangs. On analysis, found it got hanged in the redisBufferRead. This application act like a switch which gets the data from TCP Socket and store the same in the Redis database for recoverability.

    On netstat output, We found the SendQ of the our client has non-zero value which indicates that request has not reached redis server. This behaviour happens with INCR & INCRBY mostly.

    We opened a redis-client and did the same operation and it works fine.

    gdb output #0 0x008787a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 #1 0x001de69b in __read_nocancel () from /lib/tls/libpthread.so.0 #2 0x08073a42 in redisBufferRead (c=0x89c2fb8) at hiredis.c:1142 #3 0x08073c59 in redisGetReply (c=0x89c2fb8, reply=0x590dcbc) at hiredis.c:1228 #4 0x08073e99 in redisvCommand (c=0x89c2fb8, format=0x8077f40 "INCRBY %s %ld", ap=0x590dcf8 "t\021\225\b\001") at hiredis.c:1332 #5 0x08073ed2 in redisCommand (c=0x89c2fb8, format=0x8077f40 "INCRBY %s %ld") at hiredis.c:1349

    opened by saravanan-elangovan 23
  • Can't build on macosx 10.7

    Can't build on macosx 10.7

    Hi! I'm getting trouble installing package on Leon. .... Running setup.py install for hiredis building 'hiredis' library /Developer/usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -O2 -fwrapv -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -Ivendor/hiredis -c vendor/hiredis/hiredis.c -o build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis/hiredis.o vendor/hiredis/hiredis.c:691:21: error: second argument to 'va_arg' is of incomplete type 'void' va_arg(ap,void); ^~~~~~~~~~~~~~~ /Developer/usr/bin/../lib/clang/3.0/include/stdarg.h:35:50: note: instantiated from: #define va_arg(ap, type) builtin_va_arg(ap, type) ^ vendor/hiredis/hiredis.c:691:31: note: instantiated from: va_arg(ap,void); ^~~~ 1 error generated. error: command '/Developer/usr/bin/clang' failed with exit status 1 Complete output from command /Users/demon/Work/sportlook.ru/env/bin/python -c "import setuptools;__file='/Users/demon/Work/sportlook.ru/env/build/hiredis/setup.py';exec(compile(open(file).read().replace('\r\n', '\n'), file, 'exec'))" install --single-version-externally-managed --record /var/folders/s5/3z_j0lyx3r9__09nfn7vb7wh0000gn/T/pip-4asypi-record/install-record.txt --install-headers /Users/demon/Work/sportlook.ru/env/bin/../include/site/python2.7: running install

    running build

    running build_py

    creating build

    creating build/lib.macosx-10.7-x86_64-2.7

    creating build/lib.macosx-10.7-x86_64-2.7/hiredis

    copying hiredis/init.py -> build/lib.macosx-10.7-x86_64-2.7/hiredis

    copying hiredis/version.py -> build/lib.macosx-10.7-x86_64-2.7/hiredis

    running build_clib

    building 'hiredis' library

    creating build/temp.macosx-10.7-x86_64-2.7

    creating build/temp.macosx-10.7-x86_64-2.7/vendor

    creating build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis

    /Developer/usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -O2 -fwrapv -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -Ivendor/hiredis -c vendor/hiredis/hiredis.c -o build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis/hiredis.o

    vendor/hiredis/hiredis.c:691:21: error: second argument to 'va_arg' is of incomplete type 'void'

                    va_arg(ap,void);
    
                    ^~~~~~~~~~~~~~~
    

    /Developer/usr/bin/../lib/clang/3.0/include/stdarg.h:35:50: note: instantiated from:

    define va_arg(ap, type) __builtin_va_arg(ap, type)

                                                 ^
    

    vendor/hiredis/hiredis.c:691:31: note: instantiated from:

                    va_arg(ap,void);
    
                              ^~~~
    

    1 error generated.

    error: command '/Developer/usr/bin/clang' failed with exit status 1


    Command /Users/demon/Work/sportlook.ru/env/bin/python -c "import setuptools;file='/Users/demon/Work/sportlook.ru/env/build/hiredis/setup.py';exec(compile(open(file).read().replace('\r\n', '\n'), file, 'exec'))" install --single-version-externally-managed --record /var/folders/s5/3z_j0lyx3r9__09nfn7vb7wh0000gn/T/pip-4asypi-record/install-record.txt --install-headers /Users/demon/Work/sportlook.ru/env/bin/../include/site/python2.7 failed with error code 1 Storing complete log in /Users/demon/.pip/pip.log

    opened by demon-mhm 23
  • Hiredis 0.12.0

    Hiredis 0.12.0

    Hey everybody,

    I have created a develop branch for hiredis, and would like to get this going by going through a variety of outstanding issues and pull requests to see what we might want to get tested and incorporated for the next official release :smiley_cat:!

    Things I'm pretty sure we should merge:

    • #286 -- This one looks good. I agree with @mattsta that we should probably backport dict.c from Redis, but it seems reasonable to incorporate this one first (as it's a quick one).
    • #285, #282, #267 -- Just a tiny grammar fixes, but they look correct to me, so we should merge.
    • #268 -- I need to test this one, but generally speaking I like being idiomatic and using const char * vs. char * so it's clear that the string isn't going to be modified.
    • #260 -- We've been using this in production for ages, and as of yet it has not ruined everything. I think we should merge.
    • #251 -- This fixes a libuv compile error, and I favor it over the similar #258 as the non-static declaration isn't necessary at all as far as I can tell.

    Things we might want to merge:

    • #279 -- This is probably technically correct, but it's not something that really bothers me one way or the other. There are only a few calloc calls in hiredis, and they vary on argument order (when creating just 1 thing).
    • #264 -- This one looks fine to me, but I'm only mildly familiar with this TCP option. Just read up on it and I don't see how it would cause any issues.
    • #261 -- I vote yes on this one, but @pietern mentioned that it would break downstream packages, so I'm curious in what way that would be.
    • #254 -- I would like some input from fancier individuals such as @mattsta or @badboy. :smiley:
    • #250 -- IMHO I can see why this could be useful (in the case where a custom free was being used), but is not something I have personally run into.
    • #239 -- I'll investigate and test this myself, but on first glance it looks good.

    So that takes us back roughly a year for pull requests. I am going to familiarize myself with the ng branch next and see about moving that forward. I think however this is a good start. Most of these are very small and should be pretty safe.

    Cheers guys! Mike

    opened by michael-grunder 22
  • New hiredis maintainer?

    New hiredis maintainer?

    Hello, I created this issue in order to understand how to move forward with hiredis.

    1. I'm not maintaining it for a lot of time, if you exclude fixes that were necessary for Redis.
    2. @mattsta is more or less doing the same as me.
    3. @pietern was the one that was pushing hiredis forward, but I understand he got no time now (and we thank you, Pieter, for the work you put into it so far).

    @pietern are you ok with the idea of looking for a new maintainer? Apparently nobody is handling it right now but it is a critical piece of code since it's also part of Redis, Sentinel, the foundation of many other client libs, and so forth.

    Anyone interested to maintain it? This is not Redis, a more liberal model of development is possible, so we'll give commit access to the new maintainer that will schedule the releases and so forth.

    opened by antirez 19
  • New release?

    New release?

    Howdy -- I maintain the hiredis Debian packages. We've run into an interesting situation because redis vendors/bundles hiredis. The vendored library runs afoul of Debian policy rules, because we'd rather have redis use the system's shared hiredis to avoid unnecessary bloat. However, in trying to modify redis to use the shared/system hiredis (which is a very lightly modified 0.13.3) we've discovered that the bundled version of hiredis is API-incompatible with 0.13.3. See Debian tickets 907258 and 907259 for details of the specific issue we're trying to resolve.

    We can work around this on the Debian side by packaging up Git master as of some arbitrary SHA, but would prefer not to: as you can probably imagine that's both a headache for users who might be building third-party/"external" software against the hiredis Debian packages or package maintainers who might be (reasonably!) trying to port software based on 0.13.3 to Debian.

    Before I go raining on anyone's parade on the Debian side, is there any possibility we could twist your arm for the 1.0.0 release, or at least another 0.x release with an API compatible with the version bundled with redis? If something specific is holding up a release & it's just a question of manpower, let me know how I can help.

    opened by thomaslee 17
  • HiRedis has certain issues when called by another project that is on C89/C90

    HiRedis has certain issues when called by another project that is on C89/C90

    I'd like to re-open discussion about this: https://github.com/redis/hiredis/issues/31

    TLDR: Let's make hiredis header files C89/C90 compatible. Not the whole project.

    I have a hard requirement to go C89/C90 in a project where I'd like to use hiredis. When I try to use the hiredis header files, a number of problems emerge that are hard to work around. It would be better if hiredis's header files were C89/C90 compatible.

    This can be accomplished in a few different ways. I'd like to open discussion on this.

    Approach 1: Write a hello,world test app (not in the examples folder -- because this wouldn't be an example) that uses hiredis with compiler flags set to -std=c90 -pedantic to start (potentially other flags to increase the strictness of the header files) If this .c file creates compiler warnings, they can be caught by developers during check-in time.

    Approach 2 Append certain compiler flags to the Makefile. This would have a broader impact on the project. Where it says: WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings Add some compiler flags such as: -pedantic-errors -Werror -Wextra -Werror -Wmissing-prototypes -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wfloat-equal -Wconversion -Wno-missing-braces -Wold-style-definition -Wdeclaration-after-statement (The appropriate list of flags is debatable)

    Approach 3 Make the examples C89/C90 compliant by adding compiler flags just on the examples.

    opened by dagostinelli 16
  • core dump on calling sdsMakeRoomFor

    core dump on calling sdsMakeRoomFor

    I am getting core dump on realloc of sdsMakeRoomFor. My coredump backtrace is given below: `Program received signal SIGABRT, Aborted. [Switching to Thread 0x7ffff67a5700 (LWP 11207)] 0x0000003fc8c32625 in raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); (gdb) bt #0 0x0000003fc8c32625 in raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x0000003fc8c33e05 in abort () at abort.c:92 #2 0x0000003fc8c70537 in __libc_message (do_abort=2, fmt=0x3fc8d588c0 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:198 #3 0x0000003fc8c75f4e in malloc_printerr (action=3, str=0x3fc8d5687d "corrupted double-linked list", ptr=, ar_ptr=) at malloc.c:6350 #4 0x0000003fc8c763d3 in malloc_consolidate (av=0x7ffff0000020) at malloc.c:5216 #5 0x0000003fc8c79c28 in _int_malloc (av=0x7ffff0000020, bytes=) at malloc.c:4415 #6 0x0000003fc8c7bbda in _int_realloc (av=0x7ffff0000020, oldp=0x7ffff0000b60, oldsize=, nb=1312) at malloc.c:5339 #7 0x0000003fc8c7bf78 in __libc_realloc (oldmem=0x7ffff0000b70, bytes=1299) at malloc.c:3823

    #8 0x00000000004c7c06 in sdsMakeRoomFor (s=, addlen=) at sds.c:142

    #9 0x00000000004c8044 in sdscatlen (s=, t=0x7fffea673080, len=43) at sds.c:241 #10 0x00000000004c5e00 in __redisAppendCommand (c=0x735090, cmd=, len=) at hiredis.c:910 #11 0x00000000004c703c in redisvAppendCommand (c=0x735090, format=, ap=) at hiredis.c:942 #12 0x00000000004c7208 in redisAppendCommand (c=, format=) at hiredis.c:956 #13 0x0000000000446e88 in DataReader::Do (this=0x7ffff6742f50, task=0x7ffff5da3c50) at schsv_dtsvr_V1.0.0/ds/datareader.cpp:106 #14 0x000000000044d1f9 in TaskHandler::Do (p=) at schsv_dtsvr_V1.0.0/ds/task_handler.cpp:41 #15 0x0000003fc9007a51 in start_thread (arg=0x7ffff67a5700) at pthread_create.c:301 #16 0x0000003fc8ce893d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115`

    I have worked on the issue for a long time without no progress. Any idea? Thanks!

    opened by fenglonz 15
  • Wrapping OpenSSL global state initialisation?

    Wrapping OpenSSL global state initialisation?

    Current TLS support in hiredis offers two ways to trigger the OpenSSL global state initialisation:

    • Do it implicitly when calling redisSecureConnection().
    • Do it explicitly calling SSL_library_init() on your own (if that's not already done by another component) and then use redisInitiateSSL() to set up Redis connections.

    In order to avoid unwanted dependencies, it would be very convenient to hide the explicit call to SSL_library_init() in a public hiredis symbol. In other words, wrap the following logic + state from ssl.c in a function and expose it via hiredis.h.

        static int isInit = 0;
        if (!isInit) {
            isInit = 1;
            SSL_library_init();
    #ifdef HIREDIS_USE_CRYPTO_LOCKS
            initOpensslLocks();
    #endif
    

    I'm not very familiar with hiredis internals, but if you agree with the proposal I could try to submit a PR :)

    opened by carlosabalde 14
  • setsockopt(TCP_NODELAY) in Windows

    setsockopt(TCP_NODELAY) in Windows

    There appears to be a Windows-specific issue setting TCP_NODELAY in non-blocking mode.

    See related issues #736, #779.

    Yielding the timeslice (with _sleep(0)) solves the problem, but I have not been able to verify if it is the correct way to solve the problem.

    If it is correct, perhaps adding it to win32_setsockopt is the cleanest solution:

    diff --git sockcompat.c sockcompat.c
    index f99d14b..b7990b8 100644
    --- sockcompat.c
    +++ sockcompat.c
    @@ -216,6 +216,10 @@ int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval,
             DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
             ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
         } else {
    +#if _MSC_VER
    +        /* Windows workaround */
    +        if (optname == TCP_NODELAY) _sleep(0);
    +#endif
             ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
         }
         _updateErrno(ret != SOCKET_ERROR);
    

    @mbitsnbites Do you mind weighing in as you wrote the windows compatibility layer?

    Also curious if @mnunberg or @yossigo have opinions one way or the other.

    opened by michael-grunder 14
  • SEGV issue detected in redisFormatCommand function of /src/hiredis/hiredis.c:569:11

    SEGV issue detected in redisFormatCommand function of /src/hiredis/hiredis.c:569:11

    When I use fuzzing/format_command_fuzzer.c for fuzz testing, I found SEGV issue in redisFormatCommand function of /src/hiredis/hiredis.c:569:11

    POC file:

    https://github.com/HotSpurzzZ/testcases/blob/main/hiredis/hiredis_SEGV_redisFormatCommand

    Verification steps :

    export CC=/usr/bin/clang
    export CFLAGS='-fsanitize=address -g'
    export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
    git clone --depth 1 https://github.com/redis/hiredis
    cd hiredis
    make USE_SSL=0
    mv fuzzing/format_command_fuzzer.c .
    
    $CC $CFLAGS -std=c99 -pedantic -c -O3 -fPIC \
    	format_command_fuzzer.c -o format_command_fuzzer.o
    
    $CC $CFLAGS -O3 -fPIC $LIB_FUZZING_ENGINE format_command_fuzzer.o \
    	-o $OUT/format_command_fuzzer libhiredis.a
    ./format_command_fuzzer $POC
    

    AddressSanitizer output :

    $ ./format_command_fuzzer hiredis_SEGV_redisFormatCommand 
    INFO: Seed: 3825104811
    ./format_command_fuzzer: Running 1 inputs 1 time(s) each.
    Running: hiredis_SEGV_redisFormatCommand
    AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==29340==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000801 (pc 0x7f1529080c0c bp 0x7ffdbb549de0 sp 0x7ffdbb549598 T0)
    ==29340==The signal is caused by a READ memory access.
    ==29340==Hint: address points to the zero page.
        #0 0x7f1529080c0c  /build/glibc-SzIz7B/glibc-2.31/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:287
        #1 0x4bbec7 in memcpy (/root/Desktop/hiredis/format_command_fuzzer+0x4bbec7)
        #2 0x553076 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:10
        #3 0x553076 in sdscatlen /root/Desktop/hiredis/sds.c:386:5
        #4 0x54fcfa in redisvFormatCommand /root/Desktop/hiredis/hiredis.c:376:30
        #5 0x550677 in redisFormatCommand /root/Desktop/hiredis/hiredis.c:569:11
        #6 0x54f1f6 in LLVMFuzzerTestOneInput /root/Desktop/hiredis/format_command_fuzzer.c:51:9
        #7 0x458841 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/root/Desktop/hiredis/format_command_fuzzer+0x458841)
        #8 0x443f52 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/root/Desktop/hiredis/format_command_fuzzer+0x443f52)
        #9 0x449fbe in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/root/Desktop/hiredis/format_command_fuzzer+0x449fbe)
        #10 0x471a82 in main (/root/Desktop/hiredis/format_command_fuzzer+0x471a82)
        #11 0x7f1528fe9082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
        #12 0x41e65d in _start (/root/Desktop/hiredis/format_command_fuzzer+0x41e65d)
    
    AddressSanitizer can not provide additional info.
    SUMMARY: AddressSanitizer: SEGV /build/glibc-SzIz7B/glibc-2.31/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:287 
    ==29340==ABORTING
    
    opened by HotSpurzzZ 0
  • SEGV in redisvFormatCommand

    SEGV in redisvFormatCommand

    An access wild address issue occurred while testing with fuzz. The specific logs are as follows: ==2229501==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000201 (pc 0x7faebd07c8c1 bp 0x7fffd934d9d0 sp 0x7fffd934d188 T0) ==2229501==The signal is caused by a READ memory access. ==2229501==Hint: address points to the zero page. #0 0x7faebd07c8c1 (/lib64/libc.so.6+0x15b8c1) #1 0x4b7a98 in strlen /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc #2 0x552086 in redisvFormatCommand /src/hiredis/hiredis.c:357:24 #3 0x55373e in redisFormatCommand /src/hiredis/hiredis.c:554:11 #4 0x551379 in LLVMFuzzerTestOneInput /src/hiredis/format_command_fuzzer.c:51:5 #5 0x459ae3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15 #6 0x445252 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:323:6 #7 0x44aef6 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:856:9 #8 0x474402 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10 #9 0x7faebcf46b26 in __libc_start_main (/lib64/libc.so.6+0x25b26) #10 0x421109 in _start (/root/oss-fuzz/build/out/hiredis/format_command_fuzzer+0x421109)

    DEDUP_TOKEN: strlen--redisvFormatCommand AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/lib64/libc.so.6+0x15b8c1) ==2229501==ABORTING

    opened by cherry530 2
  • Disconnects on timeouts

    Disconnects on timeouts

    Hello,

    While using async APIs we notice link disconnects after command timeout, and understand this is because of the existing implementation of redisAsyncHandleTimeout.

    This is a request to make this timeout behavior command specific, instead of clearing all the outstanding callbacks & closing the connection with the server.

    Thank you.

    opened by SS-TruMinds 1
  • CMake FetchContent support

    CMake FetchContent support

    Is it possible to make FetchContent support? If I use this declaration:

    FetchContent_Declare(
      hiredis
      GIT_REPOSITORY https://github.com/redis/hiredis
      GIT_TAG origin/master
      GIT_SHALLOW TRUE
    )
    
    set(DISABLE_TESTS OFF)
    
    FetchContent_MakeAvailable(hiredis)
    

    I get header files inside _deps/hiredis-src, not include/hiredis/ and this leads to build error for Redis++ library.

    feature 
    opened by ivan-ushakov 5
  • when use one redis connection exec

    when use one redis connection exec "redisCommand"occur err ,the connection will no longer be reused

    see the code below:

         ...
        // first time to use the connection ,command is invalid format
        reply = redisCommand(c,"GET personification_config%_ver");
    
        if (c->err)
        {
          printf("zhelia 1 Failed to execute cmd err : %s\n", c->errstr);
        }
        else
        {
          printf("GET personification_config_ver: %s\n", reply->str);
        }
        freeReplyObject(reply);
    
        //    c->err=0;  //  reset the c->err
    
        // second time to use the connection ,command is correct format
        reply = redisCommand(c,"GET personification_config_ver");
        if (c->err)
        {
          printf("zhelia 2 Failed to execute cmd err : %s\n", c->errstr);
        }
        else
        {
          printf("GET personification_config_ver: %s\n", reply->str);
        }
        freeReplyObject(reply);
        ...
    

    output results:

    zhelia 1 Failed to execute cmd err : Invalid format string
    zhelia 2 Failed to execute cmd err : Invalid format string
    

    it is amazing!! why the second time exec redis command get a err.

    I use gdb debug this case, find hiread how to deal:

    First time, the redis command is "GET personification_config%_ver" , '%' not match any variable parameter list, and redisvFormatCommand return -2 ,so set c->err and c->errstr;

    int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
        char *cmd;
        int len;
    
        len = redisvFormatCommand(&cmd,format,ap);
        if (len == -1) {
            __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
            return REDIS_ERR;
        } else if (len == -2) {
            __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");  //  return here ,  and set c->err and c->errstr
            return REDIS_ERR;
        }
    
        if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
            hi_free(cmd);
            return REDIS_ERR;
        }
    
        hi_free(cmd);
        return REDIS_OK;
    }
    
    
    

    It's easy to understand that the reason for the first error is that there is no valid string format.

    but second time exec command ,why it return the same err info, check the command 'GET personification_config_ver' is ok.

    so gdb debug the second redisCommand, I find it return REDIS_OK at "redisvAppendCommand" and not set c->err and c->errstr. Then debug , I see the second time it return REDIS_ERR at "redisBufferWrite".

    the function is used to write the output buffer to the socket. it will check c->err first ,in this case , it return REDIS_ERR.

    int redisBufferWrite(redisContext *c, int *done) {
    
        /* Return early when the context has seen an error. */
        if (c->err)
            return REDIS_ERR;
    
        if (sdslen(c->obuf) > 0) {
            ssize_t nwritten = c->funcs->write(c);
            if (nwritten < 0) {
                return REDIS_ERR;
            } else if (nwritten > 0) {
                if (nwritten == (ssize_t)sdslen(c->obuf)) {
                    sdsfree(c->obuf);
                    c->obuf = sdsempty();
                    if (c->obuf == NULL)
                        goto oom;
                } else {
                    if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
                }
            }
        }
        if (done != NULL) *done = (sdslen(c->obuf) == 0);
        return REDIS_OK;
    
    oom:
        __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
        return REDIS_ERR;
    }
    
    

    But where c->err is set to !0, We can easily know the first time we exec 'redisCommand' and set c->err and c->errstr.

    the second time use the same connection to exec 'redisCommand' the c->err and c->errstr and not reset , so cause the problem.

    And I make a test : reset c->err to 0 between two "redisCommand".

    
    c->err=0;  //  reset the c->err
    
    

    It work!!! output results:

    zhelia 1 Failed to execute cmd err : Invalid format string
    GET personification_config_ver: 1662544329118
    

    Maybe you will say, when one connection have err, we should not reused it , best way is rebulid one connect. but I don't think it's reasonable, there are all err type define, some err type is not fatal, the connection can be reused.

    #define REDIS_ERR_IO 1 /* Error in read or write */
    #define REDIS_ERR_EOF 3 /* End of file */
    #define REDIS_ERR_PROTOCOL 4 /* Protocol error */
    #define REDIS_ERR_OOM 5 /* Out of memory */
    #define REDIS_ERR_TIMEOUT 6 /* Timed out */
    #define REDIS_ERR_OTHER 2 /* Everything else... */
    

    Add another info, I use redis conn pool in multithreaded service, so I will reused the redis connect, when one connect have a err like 'Invalid format string' , it will make more deal request thread err.

    When the err appear , and many thread reused the thread to work and cause err .my machine memory goes up rapidly, there is a memory leak, until it crashes because OOM.

    English expression is not good, please forgive me. ^_^

    opened by Hanliangpan 1
Releases(v1.1.0)
  • v1.1.0(Nov 16, 2022)

    🐛 Bug Fixes

    • Add support for nan in RESP3 double @filipecosta90 (#1133)

    🧰 Maintenance

    • Add an example that calls redisCommandArgv @michael-grunder (#1140)
    • fix flag reference @pata00 (#1136)
    • Make freeing a NULL redisAsyncContext a no-op. @michael-grunder (#1135)
    • CI updates @bjosv (#1139)

    Contributors

    We'd like to thank all the contributors who worked on this release!

    @bjosv, @filipecosta90, @michael-grunder, @pata00 and dachui

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0-rc1(Nov 7, 2022)

    1.1.0-rc1

    Announcing Hiredis v1.1.0-rc1, with better SSL convenience, new async adapters, and a great many bug fixes.

    🚀 New Features

    • Add possibility to prefer IPv6, IPv4 or unspecified @zuiderkwast (#1096)
    • Add adapters/libhv @ithewei (#904)
    • Add timeout support to libhv adapter. @michael-grunder (#1109)
    • set default SSL verification path @adobeturchenko (#928)
    • Introduce .close method for redisContextFuncs @pizhenwei (#1094)
    • Make it possible to set SSL verify mode @stanhu (#1085)
    • Polling adapter and example @kristjanvalur (#932)
    • Unsubscribe handling in async @bjosv (#1047)
    • Add timeout support for libuv adapter @MichaelSuen-thePointer (#1016)

    🐛 Bug Fixes

    • Update for MinGW cross compile @bit0fun (#1127)
    • fixed CPP build error with adapters/libhv.h @mtdxc (#1125)
    • Fix protocol error @michael-grunder, @mtuleika-appcast (#1106)
    • Use a windows specific keepalive function. @michael-grunder (#1104)
    • Fix CMake config path on Linux. @xkszltl (#989)
    • Fix potential fault at createDoubleObject @afcidk (#964)
    • Fix some undefined behavior @jengab (#1091)
    • Copy OOM errors to redisAsyncContext when finding subscribe callback @bjosv (#1090)
    • Maintain backward compatibility with our onConnect callback. @michael-grunder (#1087)
    • Fix PUSH handler tests for Redis >= 7.0.5 @michael-grunder (#1121)
    • fix heap-buffer-overflow @zhangtaoXT5 (#957)
    • Fix heap-buffer-overflow issue in redisvFormatCommad @bjosv (#1097)
    • Polling adapter requires sockcompat.h @michael-grunder (#1095)
    • Illumos test fixes, error message difference for bad hostname test. @devnexen (#901)
    • Remove semicolon after do-while in _EL_CLEANUP @sundb (#905)
    • Stability: Support calling redisAsyncCommand and redisAsyncDisconnect from the onConnected callback @kristjanvalur (#931)
    • Fix async connect on Windows @kristjanvalur (#1073)
    • Fix warnings on Win64 @orgads (#1058)
    • Handle push notifications before or after reply. @yossigo (#1062)
    • Update hiredis sds with improvements found in redis @bjosv (#1045)
    • Avoid incorrect call to the previous reply's callback @bjosv (#1040)
    • fix building on AIX and SunOS (#1031) @scddev (#1043)
    • Allow sending commands after sending an unsubscribe @bjosv (#1036)
    • Correction for command timeout during pubsub @bjosv (#1038)
    • Fix adapters/libevent.h compilation for 64-bit Windows @pbtummillo (#937)
    • Fix integer overflow when format command larger than 4GB @sundb (#1030)
    • Handle array response during subscribe in RESP3 @bjosv (#1014)
    • Support PING while subscribing (RESP2) @bjosv (#1027)

    🧰 Maintenance

    • CI fixes in preparation of release @michael-grunder (#1130)
    • Add do while(0) protection for macros @afcidk (#959)
    • Fixup of PR734: Coverage of hiredis.c @bjosv (#1124)
    • CMake corrections for building on Windows @bjosv (#1122)
    • Install on windows fixes @bjosv (#1117)
    • Add libhv example to our standard Makefile @michael-grunder (#1108)
    • Additional include directory given by pkg-config @bjosv (#1118)
    • Use attribute when building with Clang on Windows @bjosv (#1115)
    • Minor refactor @michael-grunder (#1110)
    • Fix pkgconfig result for hiredis_ssl @bjosv (#1107)
    • Update documentation to explain redisConnectWithOptions. @michael-grunder (#1099)
    • uvadapter: reduce number of uv_poll_start calls @noxiouz (#1098)
    • Regression test for off-by-one parsing error @bugwz (#1092)
    • CMake: remove dict.c form hiredis_sources @Lipraxde (#1055)
    • Do store command timeout in the context for redisSetTimeout @catterer (#593, #1093)
    • Add GitHub Actions CI workflow for hiredis: Arm, Arm64, 386, windows. @kristjanvalur (#943)
    • CI: bump macOS runner version @SukkaW (#1079)
    • Support for generating release notes @chayim (#1083)
    • Improve example for SSL initialization in README.md @stanhu (#1084)
    • Fix README typos @bjosv (#1080)
    • fix cmake version @smmir-cent (#1050)
    • Use the same name for static and shared libraries @orgads (#1057)
    • Embed debug information in windows static .lib file @kristjanvalur (#1054)
    • Improved async documentation @kristjanvalur (#1074)
    • Fix tests so they work for Redis 7.0 @michael-grunder (#1072)
    • Use official repository for Redis package. @yossigo (#1061)
    • Whitelist hiredis repo path in cygwin @michael-grunder (#1063)
    • CentOS 8 is EOL, switch to RockyLinux @michael-grunder (#1046)
    • CMakeLists.txt: allow building without a C++ compiler @ffontaine (#872)
    • Makefile: move SSL options into a block and refine rules @pizhenwei (#997)
    • Update CMakeLists.txt for more portability @EricDeng1001 (#1005)
    • FreeBSD build fixes + CI @michael-grunder (#1026)
    • Add asynchronous test for pubsub using RESP3 @bjosv (#1012)
    • Trigger CI failure when Valgrind issues are found @bjosv (#1011)
    • Move to using make directly in Cygwin @michael-grunder (#1020)
    • Add asynchronous API tests @bjosv (#1010)
    • Correcting the build target coverage for enabled SSL @bjosv (#1009)
    • GH Actions: Run SSL tests during CI @bjosv (#1008)
    • GH: Actions - Add valgrind and CMake @michael-grunder (#1004)
    • Add Centos8 tests in GH Actions @michael-grunder (#1001)
    • We should run actions on PRs @michael-grunder (#1000)
    • Add Cygwin test in GitHub actions @michael-grunder (#999)
    • Add Windows tests in GitHub actions @michael-grunder (#996)
    • Switch to GitHub actions @michael-grunder (#995)
    • Minor refactor of CVE-2021-32765 fix. @michael-grunder (#993)
    • Remove extra comma from CMake var. @xkszltl (#988)
    • Add REDIS_OPT_PREFER_UNSPEC @michael-grunder (#1101)

    Contributors

    We'd like to thank all the contributors who worked on this release!

    @EricDeng1001, @Lipraxde, @MichaelSuen-thePointer, @SukkaW, @adobeturchenko, @afcidk, @bit0fun, @bjosv, @bugwz, @catterer, @chayim, @devnexen, @ffontaine, @ithewei, @jengab, @kristjanvalur, @michael-grunder, @noxiouz, @mtdxc, @orgads, @pbtummillo, @pizhenwei, @scddev, @smmir-cent, @stanhu, @sundb, @vturchenko, @xkszltl, @yossigo, @zhangtaoXT5, @zuiderkwast

    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Nov 2, 2022)

Owner
Redis
Redis
A redis module, similar to redis zset, but you can set multiple scores for each member to support multi-dimensional sorting

TairZset: Support multi-score sorting zset Introduction Chinese TairZset is a data structure developed based on the redis module. Compared with the na

Alibaba 58 Nov 21, 2022
Modern, asynchronous, and wicked fast C++11 client for Redis

redox Modern, asynchronous, and wicked fast C++11 client for Redis [] (https://travis-ci.org/hmartiro/redox) Redox is a C++ interface to the Redis key

Hayk Martiros 380 Nov 17, 2022
C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

Simon Ninon 1k Dec 3, 2022
Redis client written in C++

redis-plus-plus Overview Features Branches Installation Install hiredis Install redis-plus-plus Run Tests (Optional) Use redis-plus-plus In Your Proje

null 991 Nov 22, 2022
cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

CPP Redis 554 Dec 3, 2022
Aredis - a clean redis C++ client

aredis a clean redis C++ client redis_conn rc; if (rc.connect("127.0.0.1"/*host*/, 6379/*port*/, nullptr/*password*/, 1/*db*/)) { redis_command cmd;

Evan 26 Dec 10, 2021
A C++ Redis client

redis3m A C++ Redis client, born to bring my experience using Redis and C++ on a opensource library. Main goals Provide a simple and efficient wrapper

Luca Marturana 184 Apr 21, 2022
The official C++ client API for PostgreSQL.

libpqxx Welcome to libpqxx, the C++ API to the PostgreSQL database management system. Home page: http://pqxx.org/development/libpqxx/ Find libpqxx on

Jeroen Vermeulen 705 Dec 3, 2022
Beryl-cli is a client for the BerylDB database server

Beryl-cli is a client for the BerylDB database server. It offers multiple commands and is designed to be fast and user-friendly.

BerylDB 11 Oct 9, 2022
The PostgreSQL client API in modern C++

C++ client API to PostgreSQL {#mainpage} Dmitigr Pgfe (PostGres FrontEnd, hereinafter referred to as Pgfe) - is a C++ client API to PostgreSQL servers

Dmitry Igrishin 136 Nov 9, 2022
C++ client library for PostgreSQL

Welcome to taoPQ taoPQ is a lightweight C++ client library for accessing a PostgreSQL➚ database. It has no dependencies beyond libpq➚, the C applicati

The Art of C++ 231 Nov 30, 2022
Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding.

Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding.

GitHub 475 Nov 15, 2022
RediSearch is a Redis module that provides querying, secondary indexing, and full-text search for Redis.

A query and indexing engine for Redis, providing secondary indexing, full-text search, and aggregations.

null 4k Dec 1, 2022
redis-cpp is a header-only library in C++17 for Redis (and C++11 backport)

redis-cpp - lightweight C++ client library for Redis redis-cpp is a C++17 library for executing Redis commands with support for pipelines and the publ

null 76 Nov 22, 2022
A redis module, similar to redis zset, but you can set multiple scores for each member to support multi-dimensional sorting

TairZset: Support multi-score sorting zset Introduction Chinese TairZset is a data structure developed based on the redis module. Compared with the na

Alibaba 58 Nov 21, 2022
Modern, asynchronous, and wicked fast C++11 client for Redis

redox Modern, asynchronous, and wicked fast C++11 client for Redis [] (https://travis-ci.org/hmartiro/redox) Redox is a C++ interface to the Redis key

Hayk Martiros 380 Nov 17, 2022
Build a redis client by cpp:)

Redix A light redis client implement by c++. Develop Environment cmake:3.16.3 g++:9.3.0 os:ubuntu 20.04.01 reids:5.0.7 Welcome to see my talk. Benchma

null 3 Apr 15, 2022
C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

Simon Ninon 1k Dec 3, 2022
Redis client written in C++

redis-plus-plus Overview Features Branches Installation Install hiredis Install redis-plus-plus Run Tests (Optional) Use redis-plus-plus In Your Proje

null 991 Nov 22, 2022
cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

CPP Redis 554 Dec 3, 2022