From 05048633834be2be634b3e32751a08b2eef12692 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 8 Mar 2017 22:51:03 +0000 Subject: [PATCH] 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 --- .../sanitizer_common_interceptors.inc | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index a761000b54a6..a72de0dbfcc8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -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