diff options
Diffstat (limited to 'lib/sanitizer_common/sanitizer_common_interceptors.inc')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 2332 |
1 files changed, 2138 insertions, 194 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 8c0fb55f3ce9..d1c8976781c7 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -15,9 +15,16 @@ // COMMON_INTERCEPTOR_ENTER // COMMON_INTERCEPTOR_READ_RANGE // COMMON_INTERCEPTOR_WRITE_RANGE +// COMMON_INTERCEPTOR_INITIALIZE_RANGE // COMMON_INTERCEPTOR_FD_ACQUIRE // COMMON_INTERCEPTOR_FD_RELEASE +// COMMON_INTERCEPTOR_FD_ACCESS // COMMON_INTERCEPTOR_SET_THREAD_NAME +// COMMON_INTERCEPTOR_ON_EXIT +// COMMON_INTERCEPTOR_MUTEX_LOCK +// COMMON_INTERCEPTOR_MUTEX_UNLOCK +// COMMON_INTERCEPTOR_MUTEX_REPAIR +// COMMON_INTERCEPTOR_SET_PTHREAD_NAME //===----------------------------------------------------------------------===// #include "interception/interception.h" #include "sanitizer_platform_interceptors.h" @@ -28,6 +35,68 @@ #define va_copy(dst, src) ((dst) = (src)) #endif // _WIN32 +#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE +#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, p, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_FD_ACCESS +#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK +#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK +#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR +#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {} +#endif + +#if SANITIZER_INTERCEPT_STRCMP +static inline int CharCmpX(unsigned char c1, unsigned char c2) { + return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; +} + +INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2); + unsigned char c1, c2; + uptr i; + for (i = 0;; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (c1 != c2 || c1 == '\0') break; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1); + return CharCmpX(c1, c2); +} + +INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size); + unsigned char c1 = 0, c2 = 0; + uptr i; + for (i = 0; i < size; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (c1 != c2 || c1 == '\0') break; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size)); + return CharCmpX(c1, c2); +} + +#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp) +#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp) +#else +#define INIT_STRCMP +#define INIT_STRNCMP +#endif + #if SANITIZER_INTERCEPT_STRCASECMP static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { int c1_low = ToLower(c1); @@ -40,11 +109,10 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2); unsigned char c1 = 0, c2 = 0; uptr i; - for (i = 0; ; i++) { + for (i = 0;; i++) { c1 = (unsigned char)s1[i]; c2 = (unsigned char)s2[i]; - if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') - break; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; } COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1); @@ -59,16 +127,15 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) { for (i = 0; i < n; i++) { c1 = (unsigned char)s1[i]; c2 = (unsigned char)s2[i]; - if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') - break; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; } COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n)); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n)); return CharCaseCmp(c1, c2); } -#define INIT_STRCASECMP INTERCEPT_FUNCTION(strcasecmp) -#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp) +#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp) +#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp) #else #define INIT_STRCASECMP #define INIT_STRNCASECMP @@ -83,10 +150,10 @@ INTERCEPTOR(double, frexp, double x, int *exp) { return res; } -#define INIT_FREXP INTERCEPT_FUNCTION(frexp); +#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp); #else #define INIT_FREXP -#endif // SANITIZER_INTERCEPT_FREXP +#endif // SANITIZER_INTERCEPT_FREXP #if SANITIZER_INTERCEPT_FREXPF_FREXPL INTERCEPTOR(float, frexpf, float x, int *exp) { @@ -105,25 +172,45 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) { return res; } -#define INIT_FREXPF_FREXPL \ - INTERCEPT_FUNCTION(frexpf); \ - INTERCEPT_FUNCTION(frexpl) +#define INIT_FREXPF_FREXPL \ + COMMON_INTERCEPT_FUNCTION(frexpf); \ + COMMON_INTERCEPT_FUNCTION(frexpl) #else #define INIT_FREXPF_FREXPL -#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL +#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL + +#if SI_NOT_WINDOWS +static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec, + SIZE_T iovlen, SIZE_T maxlen) { + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz); + maxlen -= sz; + } +} + +static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec, + SIZE_T iovlen, SIZE_T maxlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen); + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz); + maxlen -= sz; + } +} +#endif #if SANITIZER_INTERCEPT_READ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); SSIZE_T res = REAL(read)(fd, ptr, count); - if (res > 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); - if (res >= 0 && fd >= 0) - COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); return res; } -#define INIT_READ INTERCEPT_FUNCTION(read) +#define INIT_READ COMMON_INTERCEPT_FUNCTION(read) #else #define INIT_READ #endif @@ -132,14 +219,13 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); SSIZE_T res = REAL(pread)(fd, ptr, count, offset); - if (res > 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); - if (res >= 0 && fd >= 0) - COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); return res; } -#define INIT_PREAD INTERCEPT_FUNCTION(pread) +#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread) #else #define INIT_PREAD #endif @@ -148,30 +234,77 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); SSIZE_T res = REAL(pread64)(fd, ptr, count, offset); - if (res > 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); - if (res >= 0 && fd >= 0) - COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); return res; } -#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64) +#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64) #else #define INIT_PREAD64 #endif +#if SANITIZER_INTERCEPT_READV +INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov, + int iovcnt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(readv)(fd, iov, iovcnt); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv) +#else +#define INIT_READV +#endif + +#if SANITIZER_INTERCEPT_PREADV +INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv) +#else +#define INIT_PREADV +#endif + +#if SANITIZER_INTERCEPT_PREADV64 +INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64) +#else +#define INIT_PREADV64 +#endif + #if SANITIZER_INTERCEPT_WRITE INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count); - if (fd >= 0) - COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); SSIZE_T res = REAL(write)(fd, ptr, count); - if (res > 0) - COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + // FIXME: this check should be _before_ the call to REAL(write), not after + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); return res; } -#define INIT_WRITE INTERCEPT_FUNCTION(write) +#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write) #else #define INIT_WRITE #endif @@ -180,14 +313,13 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset); - if (fd >= 0) - COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset); - if (res > 0) - COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); return res; } -#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite) +#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite) #else #define INIT_PWRITE #endif @@ -197,22 +329,69 @@ INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count, OFF64_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset); - if (fd >= 0) - COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset); - if (res > 0) - COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); return res; } -#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64) +#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64) #else #define INIT_PWRITE64 #endif +#if SANITIZER_INTERCEPT_WRITEV +INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov, + int iovcnt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(writev)(fd, iov, iovcnt); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev) +#else +#define INIT_WRITEV +#endif + +#if SANITIZER_INTERCEPT_PWRITEV +INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev) +#else +#define INIT_PWRITEV +#endif + +#if SANITIZER_INTERCEPT_PWRITEV64 +INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64) +#else +#define INIT_PWRITEV64 +#endif + #if SANITIZER_INTERCEPT_PRCTL -INTERCEPTOR(int, prctl, int option, - unsigned long arg2, unsigned long arg3, // NOLINT - unsigned long arg4, unsigned long arg5) { // NOLINT +INTERCEPTOR(int, prctl, int option, unsigned long arg2, + unsigned long arg3, // NOLINT + unsigned long arg4, unsigned long arg5) { // NOLINT void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); static const int PR_SET_NAME = 15; @@ -225,11 +404,10 @@ INTERCEPTOR(int, prctl, int option, } return res; } -#define INIT_PRCTL INTERCEPT_FUNCTION(prctl) +#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) #else #define INIT_PRCTL -#endif // SANITIZER_INTERCEPT_PRCTL - +#endif // SANITIZER_INTERCEPT_PRCTL #if SANITIZER_INTERCEPT_TIME INTERCEPTOR(unsigned long, time, unsigned long *t) { @@ -241,51 +419,58 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) { } return res; } -#define INIT_TIME \ - INTERCEPT_FUNCTION(time); +#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time); #else #define INIT_TIME -#endif // SANITIZER_INTERCEPT_TIME - +#endif // SANITIZER_INTERCEPT_TIME #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS -INTERCEPTOR(void *, localtime, unsigned long *timep) { +static void unpoison_tm(void *ctx, __sanitizer_tm *tm) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); + if (tm->tm_zone) { + // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone + // can point to shared memory and tsan would report a data race. + COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, tm->tm_zone, + REAL(strlen(tm->tm_zone)) + 1); + } +} +INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep); - void *res = REAL(localtime)(timep); + __sanitizer_tm *res = REAL(localtime)(timep); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz); + unpoison_tm(ctx, res); } return res; } -INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) { +INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result); - void *res = REAL(localtime_r)(timep, result); + __sanitizer_tm *res = REAL(localtime_r)(timep, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz); + unpoison_tm(ctx, res); } return res; } -INTERCEPTOR(void *, gmtime, unsigned long *timep) { +INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep); - void *res = REAL(gmtime)(timep); + __sanitizer_tm *res = REAL(gmtime)(timep); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz); + unpoison_tm(ctx, res); } return res; } -INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) { +INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result); - void *res = REAL(gmtime_r)(timep, result); + __sanitizer_tm *res = REAL(gmtime_r)(timep, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz); + unpoison_tm(ctx, res); } return res; } @@ -309,38 +494,59 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { } return res; } -INTERCEPTOR(char *, asctime, void *tm) { +INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm); char *res = REAL(asctime)(tm); if (res) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); } return res; } -INTERCEPTOR(char *, asctime_r, void *tm, char *result) { +INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result); char *res = REAL(asctime_r)(tm, result); if (res) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); } return res; } -#define INIT_LOCALTIME_AND_FRIENDS \ - INTERCEPT_FUNCTION(localtime); \ - INTERCEPT_FUNCTION(localtime_r); \ - INTERCEPT_FUNCTION(gmtime); \ - INTERCEPT_FUNCTION(gmtime_r); \ - INTERCEPT_FUNCTION(ctime); \ - INTERCEPT_FUNCTION(ctime_r); \ - INTERCEPT_FUNCTION(asctime); \ - INTERCEPT_FUNCTION(asctime_r); +#define INIT_LOCALTIME_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(localtime); \ + COMMON_INTERCEPT_FUNCTION(localtime_r); \ + COMMON_INTERCEPT_FUNCTION(gmtime); \ + COMMON_INTERCEPT_FUNCTION(gmtime_r); \ + COMMON_INTERCEPT_FUNCTION(ctime); \ + COMMON_INTERCEPT_FUNCTION(ctime_r); \ + COMMON_INTERCEPT_FUNCTION(asctime); \ + COMMON_INTERCEPT_FUNCTION(asctime_r); #else #define INIT_LOCALTIME_AND_FRIENDS -#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS +#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS + +#if SANITIZER_INTERCEPT_STRPTIME +INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm); + if (format) + COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1); + char *res = REAL(strptime)(s, format, tm); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s); + // Do not call unpoison_tm here, because strptime does not, in fact, + // initialize the entire struct tm. For example, tm_zone pointer is left + // uninitialized. + if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); + } + return res; +} +#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime); +#else +#define INIT_STRPTIME +#endif #if SANITIZER_INTERCEPT_SCANF @@ -383,9 +589,9 @@ VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap) #define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \ { \ void *ctx; \ - COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__); \ va_list ap; \ va_start(ap, format); \ + COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \ int res = vname(__VA_ARGS__, ap); \ va_end(ap); \ return res; \ @@ -411,40 +617,74 @@ INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...) SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) #endif -#define INIT_SCANF \ - INTERCEPT_FUNCTION(scanf); \ - INTERCEPT_FUNCTION(sscanf); \ - INTERCEPT_FUNCTION(fscanf); \ - INTERCEPT_FUNCTION(vscanf); \ - INTERCEPT_FUNCTION(vsscanf); \ - INTERCEPT_FUNCTION(vfscanf); \ - INTERCEPT_FUNCTION(__isoc99_scanf); \ - INTERCEPT_FUNCTION(__isoc99_sscanf); \ - INTERCEPT_FUNCTION(__isoc99_fscanf); \ - INTERCEPT_FUNCTION(__isoc99_vscanf); \ - INTERCEPT_FUNCTION(__isoc99_vsscanf); \ - INTERCEPT_FUNCTION(__isoc99_vfscanf); +#endif +#if SANITIZER_INTERCEPT_SCANF +#define INIT_SCANF \ + COMMON_INTERCEPT_FUNCTION(scanf); \ + COMMON_INTERCEPT_FUNCTION(sscanf); \ + COMMON_INTERCEPT_FUNCTION(fscanf); \ + COMMON_INTERCEPT_FUNCTION(vscanf); \ + COMMON_INTERCEPT_FUNCTION(vsscanf); \ + COMMON_INTERCEPT_FUNCTION(vfscanf); #else #define INIT_SCANF #endif +#if SANITIZER_INTERCEPT_ISOC99_SCANF +#define INIT_ISOC99_SCANF \ + COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf); +#else +#define INIT_ISOC99_SCANF +#endif + +#if SANITIZER_INTERCEPT_IOCTL +#include "sanitizer_common_interceptors_ioctl.inc" +INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg); + + CHECK(ioctl_initialized); + + // Note: TSan does not use common flags, and they are zero-initialized. + // This effectively disables ioctl handling in TSan. + if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg); + + const ioctl_desc *desc = ioctl_lookup(request); + if (!desc) Printf("WARNING: unknown ioctl %x\n", request); + + if (desc) ioctl_common_pre(ctx, desc, d, request, arg); + int res = REAL(ioctl)(d, request, arg); + // FIXME: some ioctls have different return values for success and failure. + if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg); + return res; +} +#define INIT_IOCTL \ + ioctl_init(); \ + COMMON_INTERCEPT_FUNCTION(ioctl); +#else +#define INIT_IOCTL +#endif + #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS INTERCEPTOR(void *, getpwnam, const char *name) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); void *res = REAL(getpwnam)(name); - if (res != 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz); + if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz); return res; } INTERCEPTOR(void *, getpwuid, u32 uid) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid); void *res = REAL(getpwuid)(uid); - if (res != 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz); + if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz); return res; } INTERCEPTOR(void *, getgrnam, const char *name) { @@ -452,31 +692,28 @@ INTERCEPTOR(void *, getgrnam, const char *name) { COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); void *res = REAL(getgrnam)(name); - if (res != 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz); + if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz); return res; } INTERCEPTOR(void *, getgrgid, u32 gid) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid); void *res = REAL(getgrgid)(gid); - if (res != 0) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz); + if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz); return res; } -#define INIT_GETPWNAM_AND_FRIENDS \ - INTERCEPT_FUNCTION(getpwnam); \ - INTERCEPT_FUNCTION(getpwuid); \ - INTERCEPT_FUNCTION(getgrnam); \ - INTERCEPT_FUNCTION(getgrgid); +#define INIT_GETPWNAM_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(getpwnam); \ + COMMON_INTERCEPT_FUNCTION(getpwuid); \ + COMMON_INTERCEPT_FUNCTION(getgrnam); \ + COMMON_INTERCEPT_FUNCTION(getgrgid); #else #define INIT_GETPWNAM_AND_FRIENDS #endif - #if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS -INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, - char *buf, SIZE_T buflen, void **result) { +INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, char *buf, + SIZE_T buflen, void **result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); @@ -487,8 +724,8 @@ INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, } return res; } -INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, - char *buf, SIZE_T buflen, void **result) { +INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen, + void **result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result); int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result); @@ -498,8 +735,8 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, } return res; } -INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, - char *buf, SIZE_T buflen, void **result) { +INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, char *buf, + SIZE_T buflen, void **result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); @@ -510,8 +747,8 @@ INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, } return res; } -INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, - char *buf, SIZE_T buflen, void **result) { +INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen, + void **result) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result); int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result); @@ -521,16 +758,15 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, } return res; } -#define INIT_GETPWNAM_R_AND_FRIENDS \ - INTERCEPT_FUNCTION(getpwnam_r); \ - INTERCEPT_FUNCTION(getpwuid_r); \ - INTERCEPT_FUNCTION(getgrnam_r); \ - INTERCEPT_FUNCTION(getgrgid_r); +#define INIT_GETPWNAM_R_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(getpwnam_r); \ + COMMON_INTERCEPT_FUNCTION(getpwuid_r); \ + COMMON_INTERCEPT_FUNCTION(getgrnam_r); \ + COMMON_INTERCEPT_FUNCTION(getgrgid_r); #else #define INIT_GETPWNAM_R_AND_FRIENDS #endif - #if SANITIZER_INTERCEPT_CLOCK_GETTIME INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { void *ctx; @@ -556,21 +792,20 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz); return REAL(clock_settime)(clk_id, tp); } -#define INIT_CLOCK_GETTIME \ - INTERCEPT_FUNCTION(clock_getres); \ - INTERCEPT_FUNCTION(clock_gettime); \ - INTERCEPT_FUNCTION(clock_settime); +#define INIT_CLOCK_GETTIME \ + COMMON_INTERCEPT_FUNCTION(clock_getres); \ + COMMON_INTERCEPT_FUNCTION(clock_gettime); \ + COMMON_INTERCEPT_FUNCTION(clock_settime); #else #define INIT_CLOCK_GETTIME #endif - #if SANITIZER_INTERCEPT_GETITIMER INTERCEPTOR(int, getitimer, int which, void *curr_value) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value); int res = REAL(getitimer)(which, curr_value); - if (!res) { + if (!res && curr_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); } return res; @@ -578,66 +813,134 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) { INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value); - COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz); + if (new_value) + COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz); int res = REAL(setitimer)(which, new_value, old_value); if (!res && old_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); } return res; } -#define INIT_GETITIMER \ - INTERCEPT_FUNCTION(getitimer); \ - INTERCEPT_FUNCTION(setitimer); +#define INIT_GETITIMER \ + COMMON_INTERCEPT_FUNCTION(getitimer); \ + COMMON_INTERCEPT_FUNCTION(setitimer); #else #define INIT_GETITIMER #endif - #if SANITIZER_INTERCEPT_GLOB -struct sanitizer_glob_t { - SIZE_T gl_pathc; - char **gl_pathv; -}; - -static void unpoison_glob_t(void *ctx, sanitizer_glob_t *pglob) { +static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob)); // +1 for NULL pointer at the end. - COMMON_INTERCEPTOR_WRITE_RANGE( - ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv)); + if (pglob->gl_pathv) + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv)); for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) { char *p = pglob->gl_pathv[i]; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1); } } +static THREADLOCAL __sanitizer_glob_t *pglob_copy; +static THREADLOCAL void *glob_ctx; + +static void wrapped_gl_closedir(void *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1); + pglob_copy->gl_closedir(dir); +} + +static void *wrapped_gl_readdir(void *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1); + return pglob_copy->gl_readdir(dir); +} + +static void *wrapped_gl_opendir(const char *s) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1); + COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1); + return pglob_copy->gl_opendir(s); +} + +static int wrapped_gl_lstat(const char *s, void *st) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2); + COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1); + return pglob_copy->gl_lstat(s, st); +} + +static int wrapped_gl_stat(const char *s, void *st) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2); + COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1); + return pglob_copy->gl_stat(s, st); +} + INTERCEPTOR(int, glob, const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), - sanitizer_glob_t *pglob) { + __sanitizer_glob_t *pglob) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); + __sanitizer_glob_t glob_copy = { + 0, 0, 0, + 0, wrapped_gl_closedir, wrapped_gl_readdir, + wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + pglob_copy = &glob_copy; + glob_ctx = ctx; + } int res = REAL(glob)(pattern, flags, errfunc, pglob); - if (res == 0) - unpoison_glob_t(ctx, pglob); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + } + pglob_copy = 0; + glob_ctx = 0; + if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); return res; } INTERCEPTOR(int, glob64, const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), - sanitizer_glob_t *pglob) { + __sanitizer_glob_t *pglob) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob); + __sanitizer_glob_t glob_copy = { + 0, 0, 0, + 0, wrapped_gl_closedir, wrapped_gl_readdir, + wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + pglob_copy = &glob_copy; + glob_ctx = ctx; + } int res = REAL(glob64)(pattern, flags, errfunc, pglob); - if (res == 0) - unpoison_glob_t(ctx, pglob); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + } + pglob_copy = 0; + glob_ctx = 0; + if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); return res; } -#define INIT_GLOB \ - INTERCEPT_FUNCTION(glob); \ - INTERCEPT_FUNCTION(glob64); -#else // SANITIZER_INTERCEPT_GLOB +#define INIT_GLOB \ + COMMON_INTERCEPT_FUNCTION(glob); \ + COMMON_INTERCEPT_FUNCTION(glob64); +#else // SANITIZER_INTERCEPT_GLOB #define INIT_GLOB -#endif // SANITIZER_INTERCEPT_GLOB - +#endif // SANITIZER_INTERCEPT_GLOB #if SANITIZER_INTERCEPT_WAIT // According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version @@ -652,7 +955,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) { return res; } INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, - int options) { + int options) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options); int res = REAL(waitid)(idtype, id, infop, options); @@ -673,10 +976,8 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage); int res = REAL(wait3)(status, options, rusage); if (res != -1) { - if (status) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); - if (rusage) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); + if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); } return res; } @@ -685,19 +986,17 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) { COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage); int res = REAL(wait4)(pid, status, options, rusage); if (res != -1) { - if (status) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); - if (rusage) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); + if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); } return res; } -#define INIT_WAIT \ - INTERCEPT_FUNCTION(wait); \ - INTERCEPT_FUNCTION(waitid); \ - INTERCEPT_FUNCTION(waitpid); \ - INTERCEPT_FUNCTION(wait3); \ - INTERCEPT_FUNCTION(wait4); +#define INIT_WAIT \ + COMMON_INTERCEPT_FUNCTION(wait); \ + COMMON_INTERCEPT_FUNCTION(waitid); \ + COMMON_INTERCEPT_FUNCTION(waitpid); \ + COMMON_INTERCEPT_FUNCTION(wait3); \ + COMMON_INTERCEPT_FUNCTION(wait4); #else #define INIT_WAIT #endif @@ -710,8 +1009,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) { if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz); // FIXME: figure out read size based on the address family. char *res = REAL(inet_ntop)(af, src, dst, size); - if (res) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; } INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { @@ -725,13 +1023,30 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { } return res; } -#define INIT_INET \ - INTERCEPT_FUNCTION(inet_ntop); \ - INTERCEPT_FUNCTION(inet_pton); +#define INIT_INET \ + COMMON_INTERCEPT_FUNCTION(inet_ntop); \ + COMMON_INTERCEPT_FUNCTION(inet_pton); #else #define INIT_INET #endif +#if SANITIZER_INTERCEPT_INET +INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst); + if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1); + int res = REAL(inet_aton)(cp, dst); + if (res != 0) { + uptr sz = __sanitizer_in_addr_sz(af_inet); + if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz); + } + return res; +} +#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton); +#else +#define INIT_INET_ATON +#endif + #if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { void *ctx; @@ -743,7 +1058,8 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { } return res; } -#define INIT_PTHREAD_GETSCHEDPARAM INTERCEPT_FUNCTION(pthread_getschedparam); +#define INIT_PTHREAD_GETSCHEDPARAM \ + COMMON_INTERCEPT_FUNCTION(pthread_getschedparam); #else #define INIT_PTHREAD_GETSCHEDPARAM #endif @@ -760,12 +1076,13 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service, if (hints) COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo)); int res = REAL(getaddrinfo)(node, service, hints, out); - if (res == 0) { + if (res == 0 && out) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out)); struct __sanitizer_addrinfo *p = *out; while (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_addrinfo)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); if (p->ai_addr) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, struct_sockaddr_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen); if (p->ai_canonname) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname, REAL(strlen)(p->ai_canonname) + 1); @@ -774,11 +1091,34 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service, } return res; } -#define INIT_GETADDRINFO INTERCEPT_FUNCTION(getaddrinfo); +#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo); #else #define INIT_GETADDRINFO #endif +#if SANITIZER_INTERCEPT_GETNAMEINFO +INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host, + unsigned hostlen, char *serv, unsigned servlen, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen, + serv, servlen, flags); + // FIXME: consider adding READ_RANGE(sockaddr, salen) + // There is padding in in_addr that may make this too noisy + int res = + REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags); + if (res == 0) { + if (host && hostlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1); + if (serv && servlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1); + } + return res; +} +#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo); +#else +#define INIT_GETNAMEINFO +#endif + #if SANITIZER_INTERCEPT_GETSOCKNAME INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { void *ctx; @@ -791,7 +1131,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { } return res; } -#define INIT_GETSOCKNAME INTERCEPT_FUNCTION(getsockname); +#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname); #else #define INIT_GETSOCKNAME #endif @@ -837,10 +1177,10 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len, return res; } -INTERCEPTOR(struct __sanitizer_hostent *, gethostent) { +INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) { void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, gethostent); - struct __sanitizer_hostent *res = REAL(gethostent)(); + COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake); + struct __sanitizer_hostent *res = REAL(gethostent)(fake); if (res) write_hostent(ctx, res); return res; } @@ -852,11 +1192,11 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) { if (res) write_hostent(ctx, res); return res; } -#define INIT_GETHOSTBYNAME \ - INTERCEPT_FUNCTION(gethostent); \ - INTERCEPT_FUNCTION(gethostbyaddr); \ - INTERCEPT_FUNCTION(gethostbyname); \ - INTERCEPT_FUNCTION(gethostbyname2); +#define INIT_GETHOSTBYNAME \ + COMMON_INTERCEPT_FUNCTION(gethostent); \ + COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \ + COMMON_INTERCEPT_FUNCTION(gethostbyname); \ + COMMON_INTERCEPT_FUNCTION(gethostbyname2); #else #define INIT_GETHOSTBYNAME #endif @@ -935,11 +1275,11 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af, } return res; } -#define INIT_GETHOSTBYNAME_R \ - INTERCEPT_FUNCTION(gethostent_r); \ - INTERCEPT_FUNCTION(gethostbyaddr_r); \ - INTERCEPT_FUNCTION(gethostbyname_r); \ - INTERCEPT_FUNCTION(gethostbyname2_r); +#define INIT_GETHOSTBYNAME_R \ + COMMON_INTERCEPT_FUNCTION(gethostent_r); \ + COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); \ + COMMON_INTERCEPT_FUNCTION(gethostbyname_r); \ + COMMON_INTERCEPT_FUNCTION(gethostbyname2_r); #else #define INIT_GETHOSTBYNAME_R #endif @@ -956,23 +1296,1555 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen); return res; } -#define INIT_GETSOCKOPT INTERCEPT_FUNCTION(getsockopt); +#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt); #else #define INIT_GETSOCKOPT #endif +#if SANITIZER_INTERCEPT_ACCEPT +INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen); + unsigned addrlen0; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addrlen0 = *addrlen; + } + int fd2 = REAL(accept)(fd, addr, addrlen); + if (fd2 >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); + if (addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); + } + return fd2; +} +#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept); +#else +#define INIT_ACCEPT +#endif + +#if SANITIZER_INTERCEPT_ACCEPT4 +INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f); + unsigned addrlen0; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addrlen0 = *addrlen; + } + int fd2 = REAL(accept4)(fd, addr, addrlen, f); + if (fd2 >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); + if (addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); + } + return fd2; +} +#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4); +#else +#define INIT_ACCEPT4 +#endif + +#if SANITIZER_INTERCEPT_MODF +INTERCEPTOR(double, modf, double x, double *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr); + double res = REAL(modf)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +INTERCEPTOR(float, modff, float x, float *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr); + float res = REAL(modff)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +INTERCEPTOR(long double, modfl, long double x, long double *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr); + long double res = REAL(modfl)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +#define INIT_MODF \ + COMMON_INTERCEPT_FUNCTION(modf); \ + COMMON_INTERCEPT_FUNCTION(modff); \ + COMMON_INTERCEPT_FUNCTION(modfl); +#else +#define INIT_MODF +#endif + +#if SANITIZER_INTERCEPT_RECVMSG +static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg, + SSIZE_T maxlen) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg)); + if (msg->msg_name && msg->msg_namelen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen); + if (msg->msg_iov && msg->msg_iovlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov, + sizeof(*msg->msg_iov) * msg->msg_iovlen); + write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen); + if (msg->msg_control && msg->msg_controllen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen); +} + +INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, + int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags); + SSIZE_T res = REAL(recvmsg)(fd, msg, flags); + if (res >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + if (msg) write_msghdr(ctx, msg, res); + } + return res; +} +#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg); +#else +#define INIT_RECVMSG +#endif + +#if SANITIZER_INTERCEPT_GETPEERNAME +INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen); + unsigned addr_sz; + if (addrlen) addr_sz = *addrlen; + int res = REAL(getpeername)(sockfd, addr, addrlen); + if (!res && addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); + return res; +} +#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername); +#else +#define INIT_GETPEERNAME +#endif + +#if SANITIZER_INTERCEPT_SYSINFO +INTERCEPTOR(int, sysinfo, void *info) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info); + int res = REAL(sysinfo)(info); + if (!res && info) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz); + return res; +} +#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo); +#else +#define INIT_SYSINFO +#endif + +#if SANITIZER_INTERCEPT_READDIR +INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp); + __sanitizer_dirent *res = REAL(readdir)(dirp); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); + return res; +} + +INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, + __sanitizer_dirent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result); + int res = REAL(readdir_r)(dirp, entry, result); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (*result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); + } + return res; +} + +#define INIT_READDIR \ + COMMON_INTERCEPT_FUNCTION(readdir); \ + COMMON_INTERCEPT_FUNCTION(readdir_r); +#else +#define INIT_READDIR +#endif + +#if SANITIZER_INTERCEPT_READDIR64 +INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp); + __sanitizer_dirent64 *res = REAL(readdir64)(dirp); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); + return res; +} + +INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, + __sanitizer_dirent64 **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result); + int res = REAL(readdir64_r)(dirp, entry, result); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (*result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); + } + return res; +} +#define INIT_READDIR64 \ + COMMON_INTERCEPT_FUNCTION(readdir64); \ + COMMON_INTERCEPT_FUNCTION(readdir64_r); +#else +#define INIT_READDIR64 +#endif + +#if SANITIZER_INTERCEPT_PTRACE +INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); + + if (data) { + if (request == ptrace_setregs) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); + else if (request == ptrace_setfpregs) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); + else if (request == ptrace_setfpxregs) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + else if (request == ptrace_setsiginfo) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); + else if (request == ptrace_setregset) { + __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len); + } + } + + uptr res = REAL(ptrace)(request, pid, addr, data); + + if (!res && data) { + // Note that PEEK* requests assing different meaning to the return value. + // This function does not handle them (nor does it need to). + if (request == ptrace_getregs) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); + else if (request == ptrace_getfpregs) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); + else if (request == ptrace_getfpxregs) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + else if (request == ptrace_getsiginfo) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); + else if (request == ptrace_getregset) { + __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len); + } + } + return res; +} + +#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace); +#else +#define INIT_PTRACE +#endif + +#if SANITIZER_INTERCEPT_SETLOCALE +INTERCEPTOR(char *, setlocale, int category, char *locale) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale); + if (locale) + COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1); + char *res = REAL(setlocale)(category, locale); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} + +#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale); +#else +#define INIT_SETLOCALE +#endif + +#if SANITIZER_INTERCEPT_GETCWD +INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size); + char *res = REAL(getcwd)(buf, size); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd); +#else +#define INIT_GETCWD +#endif + +#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME +INTERCEPTOR(char *, get_current_dir_name, int fake) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake); + char *res = REAL(get_current_dir_name)(fake); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} + +#define INIT_GET_CURRENT_DIR_NAME \ + COMMON_INTERCEPT_FUNCTION(get_current_dir_name); +#else +#define INIT_GET_CURRENT_DIR_NAME +#endif + +#if SANITIZER_INTERCEPT_STRTOIMAX +INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base); + INTMAX_T res = REAL(strtoimax)(nptr, endptr, base); + if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); + return res; +} + +INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base); + INTMAX_T res = REAL(strtoumax)(nptr, endptr, base); + if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); + return res; +} + +#define INIT_STRTOIMAX \ + COMMON_INTERCEPT_FUNCTION(strtoimax); \ + COMMON_INTERCEPT_FUNCTION(strtoumax); +#else +#define INIT_STRTOIMAX +#endif + +#if SANITIZER_INTERCEPT_MBSTOWCS +INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len); + SIZE_T res = REAL(mbstowcs)(dest, src, len); + if (res != (SIZE_T) - 1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, + void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps); + if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps); + if (res != (SIZE_T)(-1) && dest && src) { + // This function, and several others, may or may not write the terminating + // \0 character. They write it iff they clear *src. + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +#define INIT_MBSTOWCS \ + COMMON_INTERCEPT_FUNCTION(mbstowcs); \ + COMMON_INTERCEPT_FUNCTION(mbsrtowcs); +#else +#define INIT_MBSTOWCS +#endif + +#if SANITIZER_INTERCEPT_MBSNRTOWCS +INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, + SIZE_T len, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps); + if (src) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); + } + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); + if (res != (SIZE_T)(-1) && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs); +#else +#define INIT_MBSNRTOWCS +#endif + +#if SANITIZER_INTERCEPT_WCSTOMBS +INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len); + SIZE_T res = REAL(wcstombs)(dest, src, len); + if (res != (SIZE_T) - 1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, + void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps); + if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); + if (res != (SIZE_T) - 1 && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +#define INIT_WCSTOMBS \ + COMMON_INTERCEPT_FUNCTION(wcstombs); \ + COMMON_INTERCEPT_FUNCTION(wcsrtombs); +#else +#define INIT_WCSTOMBS +#endif + +#if SANITIZER_INTERCEPT_WCSNRTOMBS +INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, + SIZE_T len, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps); + if (src) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); + } + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); + if (res != (SIZE_T) - 1 && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs); +#else +#define INIT_WCSNRTOMBS +#endif + +#if SANITIZER_INTERCEPT_TCGETATTR +INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p); + int res = REAL(tcgetattr)(fd, termios_p); + if (!res && termios_p) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz); + return res; +} + +#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr); +#else +#define INIT_TCGETATTR +#endif + +#if SANITIZER_INTERCEPT_REALPATH +INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + + // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest + // version of a versioned symbol. For realpath(), this gives us something + // (called __old_realpath) that does not handle NULL in the second argument. + // Handle it as part of the interceptor. + char *allocated_path = 0; + if (!resolved_path) + allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1); + + char *res = REAL(realpath)(path, resolved_path); + if (allocated_path && !res) WRAP(free)(allocated_path); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath); +#else +#define INIT_REALPATH +#endif + +#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME +INTERCEPTOR(char *, canonicalize_file_name, const char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + char *res = REAL(canonicalize_file_name)(path); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_CANONICALIZE_FILE_NAME \ + COMMON_INTERCEPT_FUNCTION(canonicalize_file_name); +#else +#define INIT_CANONICALIZE_FILE_NAME +#endif + +#if SANITIZER_INTERCEPT_CONFSTR +INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len); + SIZE_T res = REAL(confstr)(name, buf, len); + if (buf && res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len); + return res; +} +#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr); +#else +#define INIT_CONFSTR +#endif + +#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY +INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask); + int res = REAL(sched_getaffinity)(pid, cpusetsize, mask); + if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize); + return res; +} +#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity); +#else +#define INIT_SCHED_GETAFFINITY +#endif + +#if SANITIZER_INTERCEPT_STRERROR +INTERCEPTOR(char *, strerror, int errnum) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); + char *res = REAL(strerror)(errnum); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror); +#else +#define INIT_STRERROR +#endif + +#if SANITIZER_INTERCEPT_STRERROR_R +INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); + 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); + } + return res; +} +#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r); +#else +#define INIT_STRERROR_R +#endif + +#if SANITIZER_INTERCEPT_SCANDIR +typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *); +typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **, + const struct __sanitizer_dirent **); + +static THREADLOCAL void *scandir_ctx; +static THREADLOCAL scandir_filter_f scandir_filter; +static THREADLOCAL scandir_compar_f scandir_compar; + +static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 1); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, dir, dir->d_reclen); + return scandir_filter(dir); +} + +static int wrapped_scandir_compar(const struct __sanitizer_dirent **a, + const struct __sanitizer_dirent **b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 2); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, a, sizeof(*a)); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *a, (*a)->d_reclen); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, b, sizeof(*b)); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *b, (*b)->d_reclen); + return scandir_compar(a, b); +} + +INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist, + scandir_filter_f filter, scandir_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar); + if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); + CHECK_EQ(0, scandir_ctx); + scandir_ctx = ctx; + scandir_filter = filter; + scandir_compar = compar; + int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0, + compar ? wrapped_scandir_compar : 0); + scandir_ctx = 0; + scandir_filter = 0; + scandir_compar = 0; + if (namelist && res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); + for (int i = 0; i < res; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], + (*namelist)[i]->d_reclen); + } + return res; +} +#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir); +#else +#define INIT_SCANDIR +#endif + +#if SANITIZER_INTERCEPT_SCANDIR64 +typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *); +typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **, + const struct __sanitizer_dirent64 **); + +static THREADLOCAL void *scandir64_ctx; +static THREADLOCAL scandir64_filter_f scandir64_filter; +static THREADLOCAL scandir64_compar_f scandir64_compar; + +static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 1); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, dir, dir->d_reclen); + return scandir64_filter(dir); +} + +static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a, + const struct __sanitizer_dirent64 **b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 2); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, a, sizeof(*a)); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *a, (*a)->d_reclen); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, b, sizeof(*b)); + COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *b, (*b)->d_reclen); + return scandir64_compar(a, b); +} + +INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, + scandir64_filter_f filter, scandir64_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar); + if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); + CHECK_EQ(0, scandir64_ctx); + scandir64_ctx = ctx; + scandir64_filter = filter; + scandir64_compar = compar; + int res = + REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0, + compar ? wrapped_scandir64_compar : 0); + scandir64_ctx = 0; + scandir64_filter = 0; + scandir64_compar = 0; + if (namelist && res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); + for (int i = 0; i < res; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], + (*namelist)[i]->d_reclen); + } + return res; +} +#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64); +#else +#define INIT_SCANDIR64 +#endif + +#if SANITIZER_INTERCEPT_GETGROUPS +INTERCEPTOR(int, getgroups, int size, u32 *lst) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst); + int res = REAL(getgroups)(size, lst); + if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); + return res; +} +#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups); +#else +#define INIT_GETGROUPS +#endif + +#if SANITIZER_INTERCEPT_POLL +static void read_pollfd(void *ctx, __sanitizer_pollfd *fds, + __sanitizer_nfds_t nfds) { + for (unsigned i = 0; i < nfds; ++i) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events)); + } +} + +static void write_pollfd(void *ctx, __sanitizer_pollfd *fds, + __sanitizer_nfds_t nfds) { + for (unsigned i = 0; i < nfds; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents, + sizeof(fds[i].revents)); +} + +INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, + int timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout); + if (fds && nfds) read_pollfd(ctx, fds, nfds); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout); + if (fds && nfds) write_pollfd(ctx, fds, nfds); + return res; +} +#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll); +#else +#define INIT_POLL +#endif + +#if SANITIZER_INTERCEPT_PPOLL +INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, + void *timeout_ts, __sanitizer_sigset_t *sigmask) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask); + if (fds && nfds) read_pollfd(ctx, fds, nfds); + if (timeout_ts) + COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz); + // FIXME: read sigmask when all of sigemptyset, etc are intercepted. + int res = + COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask); + if (fds && nfds) write_pollfd(ctx, fds, nfds); + return res; +} +#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll); +#else +#define INIT_PPOLL +#endif + +#if SANITIZER_INTERCEPT_WORDEXP +INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, flags); + if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); + int res = REAL(wordexp)(s, p, flags); + if (!res && p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + if (p->we_wordc) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv, + sizeof(*p->we_wordv) * p->we_wordc); + for (uptr i = 0; i < p->we_wordc; ++i) { + char *w = p->we_wordv[i]; + if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, REAL(strlen)(w) + 1); + } + } + return res; +} +#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp); +#else +#define INIT_WORDEXP +#endif + +#if SANITIZER_INTERCEPT_SIGWAIT +INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig); + // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + int res = REAL(sigwait)(set, sig); + if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig)); + return res; +} +#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait); +#else +#define INIT_SIGWAIT +#endif + +#if SANITIZER_INTERCEPT_SIGWAITINFO +INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info); + // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + int res = REAL(sigwaitinfo)(set, info); + if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); + return res; +} +#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo); +#else +#define INIT_SIGWAITINFO +#endif + +#if SANITIZER_INTERCEPT_SIGTIMEDWAIT +INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, + void *timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout); + if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); + // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + int res = REAL(sigtimedwait)(set, info, timeout); + if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); + return res; +} +#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait); +#else +#define INIT_SIGTIMEDWAIT +#endif + +#if SANITIZER_INTERCEPT_SIGSETOPS +INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set); + int res = REAL(sigemptyset)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} + +INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set); + int res = REAL(sigfillset)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} +#define INIT_SIGSETOPS \ + COMMON_INTERCEPT_FUNCTION(sigemptyset); \ + COMMON_INTERCEPT_FUNCTION(sigfillset); +#else +#define INIT_SIGSETOPS +#endif + +#if SANITIZER_INTERCEPT_SIGPENDING +INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set); + int res = REAL(sigpending)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} +#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending); +#else +#define INIT_SIGPENDING +#endif + +#if SANITIZER_INTERCEPT_SIGPROCMASK +INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); + // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + int res = REAL(sigprocmask)(how, set, oldset); + if (!res && oldset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); + return res; +} +#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask); +#else +#define INIT_SIGPROCMASK +#endif + +#if SANITIZER_INTERCEPT_BACKTRACE +INTERCEPTOR(int, backtrace, void **buffer, int size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); + int res = REAL(backtrace)(buffer, size); + if (res && buffer) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); + return res; +} + +INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size); + if (buffer && size) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer)); + char **res = REAL(backtrace_symbols)(buffer, size); + if (res && size) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); + for (int i = 0; i < size; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], REAL(strlen(res[i])) + 1); + } + return res; +} +#define INIT_BACKTRACE \ + COMMON_INTERCEPT_FUNCTION(backtrace); \ + COMMON_INTERCEPT_FUNCTION(backtrace_symbols); +#else +#define INIT_BACKTRACE +#endif + +#if SANITIZER_INTERCEPT__EXIT +INTERCEPTOR(void, _exit, int status) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, _exit, status); + int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx); + if (status == 0) status = status1; + REAL(_exit)(status); +} +#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit); +#else +#define INIT__EXIT +#endif + +#if SANITIZER_INTERCEPT_PHTREAD_MUTEX +INTERCEPTOR(int, pthread_mutex_lock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m); + int res = REAL(pthread_mutex_lock)(m); + if (res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); + if (res == 0 || res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m); + return res; +} + +INTERCEPTOR(int, pthread_mutex_unlock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m); + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); + return REAL(pthread_mutex_unlock)(m); +} + +#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock) +#define INIT_PTHREAD_MUTEX_UNLOCK \ + COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock) +#else +#define INIT_PTHREAD_MUTEX_LOCK +#define INIT_PTHREAD_MUTEX_UNLOCK +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_COND +INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_wait, c, m); + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); + COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz); + int res = REAL(pthread_cond_wait)(c, m); + COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m); + return res; +} + +INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_init, c, a); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, pthread_cond_t_sz); + return REAL(pthread_cond_init)(c, a); +} + +INTERCEPTOR(int, pthread_cond_signal, void *c) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_signal, c); + COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz); + return REAL(pthread_cond_signal)(c); +} + +INTERCEPTOR(int, pthread_cond_broadcast, void *c) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_broadcast, c); + COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz); + return REAL(pthread_cond_broadcast)(c); +} + +#define INIT_PTHREAD_COND_WAIT \ + INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2") +#define INIT_PTHREAD_COND_INIT \ + INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2") +#define INIT_PTHREAD_COND_SIGNAL \ + INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2") +#define INIT_PTHREAD_COND_BROADCAST \ + INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2") +#else +#define INIT_PTHREAD_COND_WAIT +#define INIT_PTHREAD_COND_INIT +#define INIT_PTHREAD_COND_SIGNAL +#define INIT_PTHREAD_COND_BROADCAST +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R +static void write_mntent(void *ctx, __sanitizer_mntent *mnt) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt)); + if (mnt->mnt_fsname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname, + REAL(strlen)(mnt->mnt_fsname) + 1); + if (mnt->mnt_dir) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir, + REAL(strlen)(mnt->mnt_dir) + 1); + if (mnt->mnt_type) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type, + REAL(strlen)(mnt->mnt_type) + 1); + if (mnt->mnt_opts) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts, + REAL(strlen)(mnt->mnt_opts) + 1); +} +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT +INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp); + __sanitizer_mntent *res = REAL(getmntent)(fp); + if (res) write_mntent(ctx, res); + return res; +} +#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent); +#else +#define INIT_GETMNTENT +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT_R +INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp, + __sanitizer_mntent *mntbuf, char *buf, int buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen); + __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen); + if (res) write_mntent(ctx, res); + return res; +} +#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r); +#else +#define INIT_GETMNTENT_R +#endif + +#if SANITIZER_INTERCEPT_STATFS +INTERCEPTOR(int, statfs, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + int res = REAL(statfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); + return res; +} +INTERCEPTOR(int, fstatfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf); + int res = REAL(fstatfs)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); + return res; +} +#define INIT_STATFS \ + COMMON_INTERCEPT_FUNCTION(statfs); \ + COMMON_INTERCEPT_FUNCTION(fstatfs); +#else +#define INIT_STATFS +#endif + +#if SANITIZER_INTERCEPT_STATFS64 +INTERCEPTOR(int, statfs64, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + int res = REAL(statfs64)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); + return res; +} +INTERCEPTOR(int, fstatfs64, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf); + int res = REAL(fstatfs64)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); + return res; +} +#define INIT_STATFS64 \ + COMMON_INTERCEPT_FUNCTION(statfs64); \ + COMMON_INTERCEPT_FUNCTION(fstatfs64); +#else +#define INIT_STATFS64 +#endif + +#if SANITIZER_INTERCEPT_STATVFS +INTERCEPTOR(int, statvfs, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + int res = REAL(statvfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + return res; +} +INTERCEPTOR(int, fstatvfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); + int res = REAL(fstatvfs)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + return res; +} +#define INIT_STATVFS \ + COMMON_INTERCEPT_FUNCTION(statvfs); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs); +#else +#define INIT_STATVFS +#endif + +#if SANITIZER_INTERCEPT_STATVFS64 +INTERCEPTOR(int, statvfs64, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + int res = REAL(statvfs64)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); + return res; +} +INTERCEPTOR(int, fstatvfs64, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf); + int res = REAL(fstatvfs64)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); + return res; +} +#define INIT_STATVFS64 \ + COMMON_INTERCEPT_FUNCTION(statvfs64); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs64); +#else +#define INIT_STATVFS64 +#endif + +#if SANITIZER_INTERCEPT_INITGROUPS +INTERCEPTOR(int, initgroups, char *user, u32 group) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group); + if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1); + int res = REAL(initgroups)(user, group); + return res; +} +#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups); +#else +#define INIT_INITGROUPS +#endif + +#if SANITIZER_INTERCEPT_ETHER +INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + char *res = REAL(ether_ntoa)(addr); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf); + if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1); + __sanitizer_ether_addr *res = REAL(ether_aton)(buf); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, sizeof(*res)); + return res; +} +INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + int res = REAL(ether_ntohost)(hostname, addr); + if (!res && hostname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); + return res; +} +INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr); + if (hostname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); + int res = REAL(ether_hostton)(hostname, addr); + if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + return res; +} +INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, + char *hostname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname); + if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1); + int res = REAL(ether_line)(line, addr, hostname); + if (!res) { + if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + if (hostname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); + } + return res; +} +#define INIT_ETHER \ + COMMON_INTERCEPT_FUNCTION(ether_ntoa); \ + COMMON_INTERCEPT_FUNCTION(ether_aton); \ + COMMON_INTERCEPT_FUNCTION(ether_ntohost); \ + COMMON_INTERCEPT_FUNCTION(ether_hostton); \ + COMMON_INTERCEPT_FUNCTION(ether_line); +#else +#define INIT_ETHER +#endif + +#if SANITIZER_INTERCEPT_ETHER_R +INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + char *res = REAL(ether_ntoa_r)(addr, buf); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, + __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr); + if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1); + __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res)); + return res; +} +#define INIT_ETHER_R \ + COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \ + COMMON_INTERCEPT_FUNCTION(ether_aton_r); +#else +#define INIT_ETHER_R +#endif + +#if SANITIZER_INTERCEPT_SHMCTL +INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf); + int res = REAL(shmctl)(shmid, cmd, buf); + if (res >= 0) { + unsigned sz = 0; + if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat) + sz = sizeof(__sanitizer_shmid_ds); + else if (cmd == shmctl_ipc_info) + sz = struct_shminfo_sz; + else if (cmd == shmctl_shm_info) + sz = struct_shm_info_sz; + if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz); + } + return res; +} +#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl); +#else +#define INIT_SHMCTL +#endif + +#if SANITIZER_INTERCEPT_RANDOM_R +INTERCEPTOR(int, random_r, void *buf, u32 *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result); + int res = REAL(random_r)(buf, result); + if (!res && result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r); +#else +#define INIT_RANDOM_R +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED +#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \ + INTERCEPTOR(int, pthread_attr_get##what, void *attr, void *r) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_get##what, attr, r); \ + int res = REAL(pthread_attr_get##what)(attr, r); \ + if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \ + return res; \ + } +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET +INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int)) +INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T)) +INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz) +INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int)) +INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int)) +INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T)) +INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size); + int res = REAL(pthread_attr_getstack)(attr, addr, size); + if (!res) { + if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size)); + } + return res; +} + +#define INIT_PTHREAD_ATTR_GET \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack); +#else +#define INIT_PTHREAD_ATTR_GET +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED +INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int)) + +#define INIT_PTHREAD_ATTR_GETINHERITSCHED \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched); +#else +#define INIT_PTHREAD_ATTR_GETINHERITSCHED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP +INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, + void *cpuset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize, + cpuset); + int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset); + if (!res && cpusetsize && cpuset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize); + return res; +} + +#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np); +#else +#define INIT_PTHREAD_ATTR_GETAFFINITY_NP +#endif + +#if SANITIZER_INTERCEPT_TMPNAM +INTERCEPTOR(char *, tmpnam, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s); + char *res = REAL(tmpnam)(s); + if (res) { + if (s) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); + else + COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1); + } + return res; +} +#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam); +#else +#define INIT_TMPNAM +#endif + +#if SANITIZER_INTERCEPT_TMPNAM_R +INTERCEPTOR(char *, tmpnam_r, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s); + char *res = REAL(tmpnam_r)(s); + if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); + return res; +} +#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r); +#else +#define INIT_TMPNAM_R +#endif + +#if SANITIZER_INTERCEPT_TEMPNAM +INTERCEPTOR(char *, tempnam, char *dir, char *pfx) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx); + if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1); + if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1); + char *res = REAL(tempnam)(dir, pfx); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam); +#else +#define INIT_TEMPNAM +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP +INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name); + COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name); + return REAL(pthread_setname_np)(thread, name); +} +#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); +#else +#define INIT_PTHREAD_SETNAME_NP +#endif + +#if SANITIZER_INTERCEPT_SINCOS +INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos); + REAL(sincos)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos); + REAL(sincosf)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos); + REAL(sincosl)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +#define INIT_SINCOS \ + COMMON_INTERCEPT_FUNCTION(sincos); \ + COMMON_INTERCEPT_FUNCTION(sincosf); \ + COMMON_INTERCEPT_FUNCTION(sincosl); +#else +#define INIT_SINCOS +#endif + +#if SANITIZER_INTERCEPT_REMQUO +INTERCEPTOR(double, remquo, double x, double y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo); + double res = REAL(remquo)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +INTERCEPTOR(float, remquof, float x, float y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo); + float res = REAL(remquof)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo); + long double res = REAL(remquol)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +#define INIT_REMQUO \ + COMMON_INTERCEPT_FUNCTION(remquo); \ + COMMON_INTERCEPT_FUNCTION(remquof); \ + COMMON_INTERCEPT_FUNCTION(remquol); +#else +#define INIT_REMQUO +#endif + +#if SANITIZER_INTERCEPT_LGAMMA +extern int signgam; +INTERCEPTOR(double, lgamma, double x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x); + double res = REAL(lgamma)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +INTERCEPTOR(float, lgammaf, float x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x); + float res = REAL(lgammaf)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +INTERCEPTOR(long double, lgammal, long double x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x); + long double res = REAL(lgammal)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +#define INIT_LGAMMA \ + COMMON_INTERCEPT_FUNCTION(lgamma); \ + COMMON_INTERCEPT_FUNCTION(lgammaf); \ + COMMON_INTERCEPT_FUNCTION(lgammal); +#else +#define INIT_LGAMMA +#endif + +#if SANITIZER_INTERCEPT_LGAMMA_R +INTERCEPTOR(double, lgamma_r, double x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp); + double res = REAL(lgamma_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +INTERCEPTOR(float, lgammaf_r, float x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp); + float res = REAL(lgammaf_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +INTERCEPTOR(long double, lgammal_r, long double x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp); + long double res = REAL(lgammal_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +#define INIT_LGAMMA_R \ + COMMON_INTERCEPT_FUNCTION(lgamma_r); \ + COMMON_INTERCEPT_FUNCTION(lgammaf_r); \ + COMMON_INTERCEPT_FUNCTION(lgammal_r); +#else +#define INIT_LGAMMA_R +#endif + +#if SANITIZER_INTERCEPT_DRAND48_R +INTERCEPTOR(int, drand48_r, void *buffer, double *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result); + int res = REAL(drand48_r)(buffer, result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +INTERCEPTOR(int, lrand48_r, void *buffer, long *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result); + int res = REAL(lrand48_r)(buffer, result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +#define INIT_DRAND48_R \ + COMMON_INTERCEPT_FUNCTION(drand48_r); \ + COMMON_INTERCEPT_FUNCTION(lrand48_r); +#else +#define INIT_DRAND48_R +#endif + +#if SANITIZER_INTERCEPT_GETLINE +INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream); + SSIZE_T res = REAL(getline)(lineptr, n, stream); + if (res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); + } + return res; +} +INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, + void *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getdelim, lineptr, n, delim, stream); + SSIZE_T res = REAL(getdelim)(lineptr, n, delim, stream); + if (res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); + } + return res; +} +#define INIT_GETLINE \ + COMMON_INTERCEPT_FUNCTION(getline); \ + COMMON_INTERCEPT_FUNCTION(getdelim); +#else +#define INIT_GETLINE +#endif + #define SANITIZER_COMMON_INTERCEPTORS_INIT \ + INIT_STRCMP; \ + INIT_STRNCMP; \ INIT_STRCASECMP; \ INIT_STRNCASECMP; \ INIT_READ; \ INIT_PREAD; \ INIT_PREAD64; \ - INIT_PRCTL; \ + INIT_READV; \ + INIT_PREADV; \ + INIT_PREADV64; \ INIT_WRITE; \ INIT_PWRITE; \ INIT_PWRITE64; \ + INIT_WRITEV; \ + INIT_PWRITEV; \ + INIT_PWRITEV64; \ + INIT_PRCTL; \ INIT_LOCALTIME_AND_FRIENDS; \ + INIT_STRPTIME; \ INIT_SCANF; \ + INIT_ISOC99_SCANF; \ INIT_FREXP; \ INIT_FREXPF_FREXPL; \ INIT_GETPWNAM_AND_FRIENDS; \ @@ -985,7 +2857,79 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, INIT_INET; \ INIT_PTHREAD_GETSCHEDPARAM; \ INIT_GETADDRINFO; \ + INIT_GETNAMEINFO; \ INIT_GETSOCKNAME; \ INIT_GETHOSTBYNAME; \ INIT_GETHOSTBYNAME_R; \ - INIT_GETSOCKOPT; + INIT_GETSOCKOPT; \ + INIT_ACCEPT; \ + INIT_ACCEPT4; \ + INIT_MODF; \ + INIT_RECVMSG; \ + INIT_GETPEERNAME; \ + INIT_IOCTL; \ + INIT_INET_ATON; \ + INIT_SYSINFO; \ + INIT_READDIR; \ + INIT_READDIR64; \ + INIT_PTRACE; \ + INIT_SETLOCALE; \ + INIT_GETCWD; \ + INIT_GET_CURRENT_DIR_NAME; \ + INIT_STRTOIMAX; \ + INIT_MBSTOWCS; \ + INIT_MBSNRTOWCS; \ + INIT_WCSTOMBS; \ + INIT_WCSNRTOMBS; \ + INIT_TCGETATTR; \ + INIT_REALPATH; \ + INIT_CANONICALIZE_FILE_NAME; \ + INIT_CONFSTR; \ + INIT_SCHED_GETAFFINITY; \ + INIT_STRERROR; \ + INIT_STRERROR_R; \ + INIT_SCANDIR; \ + INIT_SCANDIR64; \ + INIT_GETGROUPS; \ + INIT_POLL; \ + INIT_PPOLL; \ + INIT_WORDEXP; \ + INIT_SIGWAIT; \ + INIT_SIGWAITINFO; \ + INIT_SIGTIMEDWAIT; \ + INIT_SIGSETOPS; \ + INIT_SIGPENDING; \ + INIT_SIGPROCMASK; \ + INIT_BACKTRACE; \ + INIT__EXIT; \ + INIT_PTHREAD_MUTEX_LOCK; \ + INIT_PTHREAD_MUTEX_UNLOCK; \ + INIT_PTHREAD_COND_WAIT; \ + INIT_PTHREAD_COND_INIT; \ + INIT_PTHREAD_COND_SIGNAL; \ + INIT_PTHREAD_COND_BROADCAST; \ + INIT_GETMNTENT; \ + INIT_GETMNTENT_R; \ + INIT_STATFS; \ + INIT_STATFS64; \ + INIT_STATVFS; \ + INIT_STATVFS64; \ + INIT_INITGROUPS; \ + INIT_ETHER; \ + INIT_ETHER_R; \ + INIT_SHMCTL; \ + INIT_RANDOM_R; \ + INIT_PTHREAD_ATTR_GET; \ + INIT_PTHREAD_ATTR_GETINHERITSCHED; \ + INIT_PTHREAD_ATTR_GETAFFINITY_NP; \ + INIT_TMPNAM; \ + INIT_TMPNAM_R; \ + INIT_TEMPNAM; \ + INIT_PTHREAD_SETNAME_NP; \ + INIT_SINCOS; \ + INIT_REMQUO; \ + INIT_LGAMMA; \ + INIT_LGAMMA_R; \ + INIT_DRAND48_R; \ + INIT_GETLINE; \ +/**/ |