Fix errno error buffers to not clobber errors
The strerror_r API has two flavors depending on system options. The bad flavor uses a static buffer for returning results, so if you save the pointer from strerror_r, the string you're referencing becomes useless if anybody else calls strerror_r again The good flavor does what you expect: it writes the error to your buffer. This commit uses strerror_r directly if it's a good version or copies the static buffer into our private buffer if it's a bad version. Thanks to gemorin for explaining the problem and drafting a fix. Fixes #239
This commit is contained in:
parent
ba3e74c408
commit
cc20232406
@ -579,7 +579,7 @@ void __redisSetError(redisContext *c, int type, const char *str) {
|
|||||||
} else {
|
} else {
|
||||||
/* Only REDIS_ERR_IO may lack a description! */
|
/* Only REDIS_ERR_IO may lack a description! */
|
||||||
assert(type == REDIS_ERR_IO);
|
assert(type == REDIS_ERR_IO);
|
||||||
strerror_r(errno,c->errstr,sizeof(c->errstr));
|
__redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
hiredis.h
24
hiredis.h
@ -76,6 +76,30 @@
|
|||||||
* SO_REUSEADDR is being used. */
|
* SO_REUSEADDR is being used. */
|
||||||
#define REDIS_CONNECT_RETRIES 10
|
#define REDIS_CONNECT_RETRIES 10
|
||||||
|
|
||||||
|
/* strerror_r has two completely different prototypes and behaviors
|
||||||
|
* depending on system issues, so we need to operate on the error buffer
|
||||||
|
* differently depending on which strerror_r we're using. */
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
/* "regular" POSIX strerror_r that does the right thing. */
|
||||||
|
#define __redis_strerror_r(errno, buf, len) \
|
||||||
|
do { \
|
||||||
|
strerror_r((errno), (buf), (len)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
/* "bad" GNU strerror_r we need to clean up after. */
|
||||||
|
#define __redis_strerror_r(errno, buf, len) \
|
||||||
|
do { \
|
||||||
|
char *err_str = strerror_r((errno), (buf), (len)); \
|
||||||
|
/* If return value _isn't_ the start of the buffer we passed in, \
|
||||||
|
* then GNU strerror_r returned an internal static buffer and we \
|
||||||
|
* need to copy the result into our private buffer. */ \
|
||||||
|
if (err_str != (buf)) { \
|
||||||
|
buf[(len)] = '\0'; \
|
||||||
|
strncat((buf), err_str, ((len) - 1)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
2
net.c
2
net.c
@ -67,7 +67,7 @@ static void __redisSetErrorFromErrno(redisContext *c, int type, const char *pref
|
|||||||
|
|
||||||
if (prefix != NULL)
|
if (prefix != NULL)
|
||||||
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
||||||
strerror_r(errno,buf+len,sizeof(buf)-len);
|
__redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len);
|
||||||
__redisSetError(c,type,buf);
|
__redisSetError(c,type,buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user