Use correct function signature for strerror_r interceptor

There are two possible return values for strerror_r:

On OS X, the return value is always `int`.
On Linux, the return value can be either `char *` or `int`, depending
on the value of:
`(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE`

Because OS X interceptors require a matching function signature,
split out the two cases into separate interceptors, using the above
information to determine the correct signature for a given build.

llvm-svn: 297315
This commit is contained in:
Francis Ricci 2017-03-08 22:51:03 +00:00
parent 260bda3fbc
commit 0504863383
1 changed files with 27 additions and 16 deletions

View File

@ -3245,6 +3245,30 @@ INTERCEPTOR(char *, strerror, int errnum) {
#endif
#if SANITIZER_INTERCEPT_STRERROR_R
// There are 2 versions of strerror_r:
// * POSIX version returns 0 on success, negative error code on failure,
// writes message to buf.
// * GNU version returns message pointer, which points to either buf or some
// static storage.
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \
SANITIZER_MAC
// POSIX version. Spec is not clear on whether buf is NULL-terminated.
// At least on OSX, buf contents are valid even when the call fails.
INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
int res = REAL(strerror_r)(errnum, buf, buflen);
SIZE_T sz = internal_strnlen(buf, buflen);
if (sz < buflen) ++sz;
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
return res;
}
#else
// GNU version.
INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
@ -3252,24 +3276,11 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
char *res = REAL(strerror_r)(errnum, buf, buflen);
// There are 2 versions of strerror_r:
// * POSIX version returns 0 on success, negative error code on failure,
// writes message to buf.
// * GNU version returns message pointer, which points to either buf or some
// static storage.
SIZE_T posix_res = (SIZE_T)res;
if (posix_res < 1024 || posix_res > (SIZE_T) - 1024) {
// POSIX version. Spec is not clear on whether buf is NULL-terminated.
// At least on OSX, buf contents are valid even when the call fails.
SIZE_T sz = internal_strnlen(buf, buflen);
if (sz < buflen) ++sz;
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
} else {
// GNU version.
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
}
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
#endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE ||
//SANITIZER_MAC
#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
#else
#define INIT_STRERROR_R