diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -5832,6 +5832,37 @@ #define INIT_XDR #endif // SANITIZER_INTERCEPT_XDR +#if SANITIZER_INTERCEPT_XDRREC_LINUX +THREADLOCAL int (*xdrrec_real_wr)(char*, char*, int); +static int xdrrec_wr_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count); + return xdrrec_real_wr(handle, buf, count); +} + +// This doesn't apply to the solaris version as it has a different function +// signature. +INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize, + unsigned rcvsize, char *handle, int (*rd)(char*, char*, int), + int (*wr)(char*, char*, int)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize, + handle, rd, wr); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op); + xdrrec_real_wr = wr; + if (wr) + wr = xdrrec_wr_wrap; + // TODO: sanitizer common doesn't have an equivalent of + // COMMON_INTERCEPTOR_READ_RANGE that doesn't need to take a context + // parameter, so we assume data written in the RD callback is fully valid + REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr); +} +#define INIT_XDRREC_LINUX \ + COMMON_INTERCEPT_FUNCTION(xdrrec_create); +#else +#define INIT_XDRREC_LINUX +#endif + #if SANITIZER_INTERCEPT_TSEARCH INTERCEPTOR(void *, tsearch, void *key, void **rootp, int (*compar)(const void *, const void *)) { @@ -10091,6 +10122,7 @@ INIT_BZERO; INIT_FTIME; INIT_XDR; + INIT_XDRREC_LINUX; INIT_TSEARCH; INIT_LIBIO_INTERNALS; INIT_FOPEN; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -440,6 +440,7 @@ #define SANITIZER_INTERCEPT_FTIME \ (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX) #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_XDRREC_LINUX SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TSEARCH \ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/xdrrec.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/xdrrec.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/xdrrec.cpp @@ -0,0 +1,26 @@ +// RUN: %clangxx -O0 %s -o %t && %run %t | FileCheck %s +#include +#include + +int print_msg(char *handle, char *buf, int len) { + if (len > 0) { + for (size_t i = 0; i < len; i++) { + printf("%02x ", (uint8_t)buf[i]); + } + printf("\n"); + } + return len; +} + +int main() { + XDR xdrs; + xdrs.x_op = XDR_ENCODE; + + xdrrec_create(&xdrs, 0, 0, nullptr, nullptr, print_msg); + unsigned foo = 42; + assert(xdr_u_int(&xdrs, &foo)); + assert(xdrrec_endofrecord(&xdrs, /*sendnow*/ true)); + xdr_destroy(&xdrs); +} + +// CHECK: 00 00 00 2a