xref: /openbsd-src/gnu/llvm/compiler-rt/lib/msan/msan_interceptors.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- msan_interceptors.cpp ---------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of MemorySanitizer.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Interceptors for standard library functions.
123cab2bb3Spatrick //
133cab2bb3Spatrick // FIXME: move as many interceptors as possible into
143cab2bb3Spatrick // sanitizer_common/sanitizer_common_interceptors.h
153cab2bb3Spatrick //===----------------------------------------------------------------------===//
163cab2bb3Spatrick 
173cab2bb3Spatrick #include "interception/interception.h"
183cab2bb3Spatrick #include "msan.h"
193cab2bb3Spatrick #include "msan_chained_origin_depot.h"
203cab2bb3Spatrick #include "msan_origin.h"
21*810390e3Srobert #include "msan_poisoning.h"
223cab2bb3Spatrick #include "msan_report.h"
233cab2bb3Spatrick #include "msan_thread.h"
243cab2bb3Spatrick #include "sanitizer_common/sanitizer_allocator.h"
25*810390e3Srobert #include "sanitizer_common/sanitizer_allocator_dlsym.h"
263cab2bb3Spatrick #include "sanitizer_common/sanitizer_allocator_interface.h"
273cab2bb3Spatrick #include "sanitizer_common/sanitizer_atomic.h"
283cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
293cab2bb3Spatrick #include "sanitizer_common/sanitizer_errno.h"
30*810390e3Srobert #include "sanitizer_common/sanitizer_errno_codes.h"
31*810390e3Srobert #include "sanitizer_common/sanitizer_glibc_version.h"
323cab2bb3Spatrick #include "sanitizer_common/sanitizer_libc.h"
333cab2bb3Spatrick #include "sanitizer_common/sanitizer_linux.h"
34*810390e3Srobert #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
35*810390e3Srobert #include "sanitizer_common/sanitizer_platform_limits_posix.h"
36*810390e3Srobert #include "sanitizer_common/sanitizer_stackdepot.h"
373cab2bb3Spatrick #include "sanitizer_common/sanitizer_tls_get_addr.h"
383cab2bb3Spatrick #include "sanitizer_common/sanitizer_vector.h"
393cab2bb3Spatrick 
403cab2bb3Spatrick #if SANITIZER_NETBSD
413cab2bb3Spatrick #define fstat __fstat50
423cab2bb3Spatrick #define gettimeofday __gettimeofday50
433cab2bb3Spatrick #define getrusage __getrusage50
443cab2bb3Spatrick #define tzset __tzset50
453cab2bb3Spatrick #endif
463cab2bb3Spatrick 
473cab2bb3Spatrick #include <stdarg.h>
483cab2bb3Spatrick // ACHTUNG! No other system header includes in this file.
493cab2bb3Spatrick // Ideally, we should get rid of stdarg.h as well.
503cab2bb3Spatrick 
513cab2bb3Spatrick using namespace __msan;
523cab2bb3Spatrick 
533cab2bb3Spatrick using __sanitizer::memory_order;
543cab2bb3Spatrick using __sanitizer::atomic_load;
553cab2bb3Spatrick using __sanitizer::atomic_store;
563cab2bb3Spatrick using __sanitizer::atomic_uintptr_t;
573cab2bb3Spatrick 
583cab2bb3Spatrick DECLARE_REAL(SIZE_T, strlen, const char *s)
593cab2bb3Spatrick DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
603cab2bb3Spatrick DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
613cab2bb3Spatrick DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
623cab2bb3Spatrick 
633cab2bb3Spatrick // True if this is a nested interceptor.
643cab2bb3Spatrick static THREADLOCAL int in_interceptor_scope;
653cab2bb3Spatrick 
__msan_scoped_disable_interceptor_checks()663cab2bb3Spatrick void __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; }
__msan_scoped_enable_interceptor_checks()673cab2bb3Spatrick void __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; }
683cab2bb3Spatrick 
693cab2bb3Spatrick struct InterceptorScope {
InterceptorScopeInterceptorScope703cab2bb3Spatrick   InterceptorScope() { ++in_interceptor_scope; }
~InterceptorScopeInterceptorScope713cab2bb3Spatrick   ~InterceptorScope() { --in_interceptor_scope; }
723cab2bb3Spatrick };
733cab2bb3Spatrick 
IsInInterceptorScope()743cab2bb3Spatrick bool IsInInterceptorScope() {
753cab2bb3Spatrick   return in_interceptor_scope;
763cab2bb3Spatrick }
773cab2bb3Spatrick 
78*810390e3Srobert struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
UseImplDlsymAlloc79*810390e3Srobert   static bool UseImpl() { return !msan_inited; }
80*810390e3Srobert };
813cab2bb3Spatrick 
823cab2bb3Spatrick #define ENSURE_MSAN_INITED() do { \
833cab2bb3Spatrick   CHECK(!msan_init_is_running); \
843cab2bb3Spatrick   if (!msan_inited) { \
853cab2bb3Spatrick     __msan_init(); \
863cab2bb3Spatrick   } \
873cab2bb3Spatrick } while (0)
883cab2bb3Spatrick 
893cab2bb3Spatrick // Check that [x, x+n) range is unpoisoned.
903cab2bb3Spatrick #define CHECK_UNPOISONED_0(x, n)                                  \
913cab2bb3Spatrick   do {                                                            \
923cab2bb3Spatrick     sptr __offset = __msan_test_shadow(x, n);                     \
93*810390e3Srobert     if (__msan::IsInSymbolizerOrUnwider())                        \
94*810390e3Srobert       break;                                                      \
953cab2bb3Spatrick     if (__offset >= 0 && __msan::flags()->report_umrs) {          \
963cab2bb3Spatrick       GET_CALLER_PC_BP_SP;                                        \
973cab2bb3Spatrick       (void)sp;                                                   \
983cab2bb3Spatrick       ReportUMRInsideAddressRange(__func__, x, n, __offset);      \
993cab2bb3Spatrick       __msan::PrintWarningWithOrigin(                             \
1003cab2bb3Spatrick           pc, bp, __msan_get_origin((const char *)x + __offset)); \
1013cab2bb3Spatrick       if (__msan::flags()->halt_on_error) {                       \
1023cab2bb3Spatrick         Printf("Exiting\n");                                      \
1033cab2bb3Spatrick         Die();                                                    \
1043cab2bb3Spatrick       }                                                           \
1053cab2bb3Spatrick     }                                                             \
1063cab2bb3Spatrick   } while (0)
1073cab2bb3Spatrick 
1083cab2bb3Spatrick // Check that [x, x+n) range is unpoisoned unless we are in a nested
1093cab2bb3Spatrick // interceptor.
1103cab2bb3Spatrick #define CHECK_UNPOISONED(x, n)                             \
1113cab2bb3Spatrick   do {                                                     \
1123cab2bb3Spatrick     if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
1133cab2bb3Spatrick   } while (0)
1143cab2bb3Spatrick 
1153cab2bb3Spatrick #define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n)               \
1163cab2bb3Spatrick   CHECK_UNPOISONED((x),                                         \
1173cab2bb3Spatrick     common_flags()->strict_string_checks ? (len) + 1 : (n) )
1183cab2bb3Spatrick 
1193cab2bb3Spatrick #define CHECK_UNPOISONED_STRING(x, n)                           \
1203cab2bb3Spatrick     CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
1213cab2bb3Spatrick 
1223cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(SIZE_T,fread_unlocked,void * ptr,SIZE_T size,SIZE_T nmemb,void * file)1233cab2bb3Spatrick INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
1243cab2bb3Spatrick             void *file) {
1253cab2bb3Spatrick   ENSURE_MSAN_INITED();
1263cab2bb3Spatrick   SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file);
1273cab2bb3Spatrick   if (res > 0)
1283cab2bb3Spatrick     __msan_unpoison(ptr, res *size);
1293cab2bb3Spatrick   return res;
1303cab2bb3Spatrick }
1313cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
1323cab2bb3Spatrick #else
1333cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
1343cab2bb3Spatrick #endif
1353cab2bb3Spatrick 
1363cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(void *,mempcpy,void * dest,const void * src,SIZE_T n)1373cab2bb3Spatrick INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
1383cab2bb3Spatrick   return (char *)__msan_memcpy(dest, src, n) + n;
1393cab2bb3Spatrick }
1403cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MEMPCPY INTERCEPT_FUNCTION(mempcpy)
1413cab2bb3Spatrick #else
1423cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MEMPCPY
1433cab2bb3Spatrick #endif
1443cab2bb3Spatrick 
INTERCEPTOR(void *,memccpy,void * dest,const void * src,int c,SIZE_T n)1453cab2bb3Spatrick INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
1463cab2bb3Spatrick   ENSURE_MSAN_INITED();
1473cab2bb3Spatrick   void *res = REAL(memccpy)(dest, src, c, n);
1483cab2bb3Spatrick   CHECK(!res || (res >= dest && res <= (char *)dest + n));
1493cab2bb3Spatrick   SIZE_T sz = res ? (char *)res - (char *)dest : n;
1503cab2bb3Spatrick   CHECK_UNPOISONED(src, sz);
1513cab2bb3Spatrick   __msan_unpoison(dest, sz);
1523cab2bb3Spatrick   return res;
1533cab2bb3Spatrick }
1543cab2bb3Spatrick 
INTERCEPTOR(void *,bcopy,const void * src,void * dest,SIZE_T n)1553cab2bb3Spatrick INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
1563cab2bb3Spatrick   return __msan_memmove(dest, src, n);
1573cab2bb3Spatrick }
1583cab2bb3Spatrick 
INTERCEPTOR(int,posix_memalign,void ** memptr,SIZE_T alignment,SIZE_T size)1593cab2bb3Spatrick INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
1603cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
1613cab2bb3Spatrick   CHECK_NE(memptr, 0);
1623cab2bb3Spatrick   int res = msan_posix_memalign(memptr, alignment, size, &stack);
1633cab2bb3Spatrick   if (!res)
1643cab2bb3Spatrick     __msan_unpoison(memptr, sizeof(*memptr));
1653cab2bb3Spatrick   return res;
1663cab2bb3Spatrick }
1673cab2bb3Spatrick 
1683cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(void *,memalign,SIZE_T alignment,SIZE_T size)1693cab2bb3Spatrick INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
1703cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
1713cab2bb3Spatrick   return msan_memalign(alignment, size, &stack);
1723cab2bb3Spatrick }
1733cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
1743cab2bb3Spatrick #else
1753cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MEMALIGN
1763cab2bb3Spatrick #endif
1773cab2bb3Spatrick 
INTERCEPTOR(void *,aligned_alloc,SIZE_T alignment,SIZE_T size)1783cab2bb3Spatrick INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
1793cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
1803cab2bb3Spatrick   return msan_aligned_alloc(alignment, size, &stack);
1813cab2bb3Spatrick }
1823cab2bb3Spatrick 
1833cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(void *,__libc_memalign,SIZE_T alignment,SIZE_T size)1843cab2bb3Spatrick INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
1853cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
1863cab2bb3Spatrick   void *ptr = msan_memalign(alignment, size, &stack);
1873cab2bb3Spatrick   if (ptr)
1883cab2bb3Spatrick     DTLS_on_libc_memalign(ptr, size);
1893cab2bb3Spatrick   return ptr;
1903cab2bb3Spatrick }
1913cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
1923cab2bb3Spatrick #else
1933cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
1943cab2bb3Spatrick #endif
1953cab2bb3Spatrick 
INTERCEPTOR(void *,valloc,SIZE_T size)1963cab2bb3Spatrick INTERCEPTOR(void *, valloc, SIZE_T size) {
1973cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
1983cab2bb3Spatrick   return msan_valloc(size, &stack);
1993cab2bb3Spatrick }
2003cab2bb3Spatrick 
2013cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(void *,pvalloc,SIZE_T size)2023cab2bb3Spatrick INTERCEPTOR(void *, pvalloc, SIZE_T size) {
2033cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
2043cab2bb3Spatrick   return msan_pvalloc(size, &stack);
2053cab2bb3Spatrick }
2063cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
2073cab2bb3Spatrick #else
2083cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PVALLOC
2093cab2bb3Spatrick #endif
2103cab2bb3Spatrick 
INTERCEPTOR(void,free,void * ptr)2113cab2bb3Spatrick INTERCEPTOR(void, free, void *ptr) {
212*810390e3Srobert   if (UNLIKELY(!ptr))
213*810390e3Srobert     return;
214*810390e3Srobert   if (DlsymAlloc::PointerIsMine(ptr))
215*810390e3Srobert     return DlsymAlloc::Free(ptr);
2163cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
2173cab2bb3Spatrick   MsanDeallocate(&stack, ptr);
2183cab2bb3Spatrick }
2193cab2bb3Spatrick 
2203cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(void,cfree,void * ptr)2213cab2bb3Spatrick INTERCEPTOR(void, cfree, void *ptr) {
222*810390e3Srobert   if (UNLIKELY(!ptr))
223*810390e3Srobert     return;
224*810390e3Srobert   if (DlsymAlloc::PointerIsMine(ptr))
225*810390e3Srobert     return DlsymAlloc::Free(ptr);
2263cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
2273cab2bb3Spatrick   MsanDeallocate(&stack, ptr);
2283cab2bb3Spatrick }
2293cab2bb3Spatrick #  define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
2303cab2bb3Spatrick #else
2313cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_CFREE
2323cab2bb3Spatrick #endif
2333cab2bb3Spatrick 
2343cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(uptr,malloc_usable_size,void * ptr)2353cab2bb3Spatrick INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
2363cab2bb3Spatrick   return __sanitizer_get_allocated_size(ptr);
2373cab2bb3Spatrick }
2383cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
2393cab2bb3Spatrick   INTERCEPT_FUNCTION(malloc_usable_size)
2403cab2bb3Spatrick #else
2413cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
2423cab2bb3Spatrick #endif
2433cab2bb3Spatrick 
2443cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
2453cab2bb3Spatrick // This function actually returns a struct by value, but we can't unpoison a
2463cab2bb3Spatrick // temporary! The following is equivalent on all supported platforms but
2473cab2bb3Spatrick // aarch64 (which uses a different register for sret value).  We have a test
2483cab2bb3Spatrick // to confirm that.
INTERCEPTOR(void,mallinfo,__sanitizer_struct_mallinfo * sret)2493cab2bb3Spatrick INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) {
2503cab2bb3Spatrick #ifdef __aarch64__
2513cab2bb3Spatrick   uptr r8;
2523cab2bb3Spatrick   asm volatile("mov %0,x8" : "=r" (r8));
2533cab2bb3Spatrick   sret = reinterpret_cast<__sanitizer_struct_mallinfo*>(r8);
2543cab2bb3Spatrick #endif
2553cab2bb3Spatrick   REAL(memset)(sret, 0, sizeof(*sret));
2563cab2bb3Spatrick   __msan_unpoison(sret, sizeof(*sret));
2573cab2bb3Spatrick }
2583cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
2593cab2bb3Spatrick #else
2603cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLINFO
2613cab2bb3Spatrick #endif
2623cab2bb3Spatrick 
2633cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(int,mallopt,int cmd,int value)2643cab2bb3Spatrick INTERCEPTOR(int, mallopt, int cmd, int value) {
2653cab2bb3Spatrick   return 0;
2663cab2bb3Spatrick }
2673cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
2683cab2bb3Spatrick #else
2693cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOPT
2703cab2bb3Spatrick #endif
2713cab2bb3Spatrick 
2723cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(void,malloc_stats,void)2733cab2bb3Spatrick INTERCEPTOR(void, malloc_stats, void) {
2743cab2bb3Spatrick   // FIXME: implement, but don't call REAL(malloc_stats)!
2753cab2bb3Spatrick }
2763cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
2773cab2bb3Spatrick #else
2783cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
2793cab2bb3Spatrick #endif
2803cab2bb3Spatrick 
INTERCEPTOR(char *,strcpy,char * dest,const char * src)2813cab2bb3Spatrick INTERCEPTOR(char *, strcpy, char *dest, const char *src) {
2823cab2bb3Spatrick   ENSURE_MSAN_INITED();
2833cab2bb3Spatrick   GET_STORE_STACK_TRACE;
284*810390e3Srobert   SIZE_T n = internal_strlen(src);
2853cab2bb3Spatrick   CHECK_UNPOISONED_STRING(src + n, 0);
2863cab2bb3Spatrick   char *res = REAL(strcpy)(dest, src);
2873cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, n + 1, &stack);
2883cab2bb3Spatrick   return res;
2893cab2bb3Spatrick }
2903cab2bb3Spatrick 
INTERCEPTOR(char *,strncpy,char * dest,const char * src,SIZE_T n)2913cab2bb3Spatrick INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) {
2923cab2bb3Spatrick   ENSURE_MSAN_INITED();
2933cab2bb3Spatrick   GET_STORE_STACK_TRACE;
294*810390e3Srobert   SIZE_T copy_size = internal_strnlen(src, n);
2953cab2bb3Spatrick   if (copy_size < n)
2963cab2bb3Spatrick     copy_size++;  // trailing \0
2973cab2bb3Spatrick   char *res = REAL(strncpy)(dest, src, n);
2983cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, copy_size, &stack);
2993cab2bb3Spatrick   __msan_unpoison(dest + copy_size, n - copy_size);
3003cab2bb3Spatrick   return res;
3013cab2bb3Spatrick }
3023cab2bb3Spatrick 
3033cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(char *,stpcpy,char * dest,const char * src)3043cab2bb3Spatrick INTERCEPTOR(char *, stpcpy, char *dest, const char *src) {
3053cab2bb3Spatrick   ENSURE_MSAN_INITED();
3063cab2bb3Spatrick   GET_STORE_STACK_TRACE;
307*810390e3Srobert   SIZE_T n = internal_strlen(src);
3083cab2bb3Spatrick   CHECK_UNPOISONED_STRING(src + n, 0);
3093cab2bb3Spatrick   char *res = REAL(stpcpy)(dest, src);
3103cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, n + 1, &stack);
3113cab2bb3Spatrick   return res;
3123cab2bb3Spatrick }
313*810390e3Srobert 
INTERCEPTOR(char *,stpncpy,char * dest,const char * src,SIZE_T n)314*810390e3Srobert INTERCEPTOR(char *, stpncpy, char *dest, const char *src, SIZE_T n) {
315*810390e3Srobert   ENSURE_MSAN_INITED();
316*810390e3Srobert   GET_STORE_STACK_TRACE;
317*810390e3Srobert   SIZE_T copy_size = Min(n, internal_strnlen(src, n) + 1);
318*810390e3Srobert   char *res = REAL(stpncpy)(dest, src, n);
319*810390e3Srobert   CopyShadowAndOrigin(dest, src, copy_size, &stack);
320*810390e3Srobert   __msan_unpoison(dest + copy_size, n - copy_size);
321*810390e3Srobert   return res;
322*810390e3Srobert }
3233cab2bb3Spatrick #  define MSAN_MAYBE_INTERCEPT_STPCPY INTERCEPT_FUNCTION(stpcpy)
324*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_STPNCPY INTERCEPT_FUNCTION(stpncpy)
3253cab2bb3Spatrick #else
3263cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_STPCPY
327*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_STPNCPY
3283cab2bb3Spatrick #endif
3293cab2bb3Spatrick 
INTERCEPTOR(char *,strdup,char * src)3303cab2bb3Spatrick INTERCEPTOR(char *, strdup, char *src) {
3313cab2bb3Spatrick   ENSURE_MSAN_INITED();
3323cab2bb3Spatrick   GET_STORE_STACK_TRACE;
3333cab2bb3Spatrick   // On FreeBSD strdup() leverages strlen().
3343cab2bb3Spatrick   InterceptorScope interceptor_scope;
335*810390e3Srobert   SIZE_T n = internal_strlen(src);
3363cab2bb3Spatrick   CHECK_UNPOISONED_STRING(src + n, 0);
3373cab2bb3Spatrick   char *res = REAL(strdup)(src);
3383cab2bb3Spatrick   CopyShadowAndOrigin(res, src, n + 1, &stack);
3393cab2bb3Spatrick   return res;
3403cab2bb3Spatrick }
3413cab2bb3Spatrick 
3423cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(char *,__strdup,char * src)3433cab2bb3Spatrick INTERCEPTOR(char *, __strdup, char *src) {
3443cab2bb3Spatrick   ENSURE_MSAN_INITED();
3453cab2bb3Spatrick   GET_STORE_STACK_TRACE;
346*810390e3Srobert   SIZE_T n = internal_strlen(src);
3473cab2bb3Spatrick   CHECK_UNPOISONED_STRING(src + n, 0);
3483cab2bb3Spatrick   char *res = REAL(__strdup)(src);
3493cab2bb3Spatrick   CopyShadowAndOrigin(res, src, n + 1, &stack);
3503cab2bb3Spatrick   return res;
3513cab2bb3Spatrick }
3523cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
3533cab2bb3Spatrick #else
3543cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___STRDUP
3553cab2bb3Spatrick #endif
3563cab2bb3Spatrick 
3573cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(char *,gcvt,double number,SIZE_T ndigit,char * buf)3583cab2bb3Spatrick INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
3593cab2bb3Spatrick   ENSURE_MSAN_INITED();
3603cab2bb3Spatrick   char *res = REAL(gcvt)(number, ndigit, buf);
361*810390e3Srobert   SIZE_T n = internal_strlen(buf);
3623cab2bb3Spatrick   __msan_unpoison(buf, n + 1);
3633cab2bb3Spatrick   return res;
3643cab2bb3Spatrick }
3653cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_GCVT INTERCEPT_FUNCTION(gcvt)
3663cab2bb3Spatrick #else
3673cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_GCVT
3683cab2bb3Spatrick #endif
3693cab2bb3Spatrick 
INTERCEPTOR(char *,strcat,char * dest,const char * src)3703cab2bb3Spatrick INTERCEPTOR(char *, strcat, char *dest, const char *src) {
3713cab2bb3Spatrick   ENSURE_MSAN_INITED();
3723cab2bb3Spatrick   GET_STORE_STACK_TRACE;
373*810390e3Srobert   SIZE_T src_size = internal_strlen(src);
374*810390e3Srobert   SIZE_T dest_size = internal_strlen(dest);
3753cab2bb3Spatrick   CHECK_UNPOISONED_STRING(src + src_size, 0);
3763cab2bb3Spatrick   CHECK_UNPOISONED_STRING(dest + dest_size, 0);
3773cab2bb3Spatrick   char *res = REAL(strcat)(dest, src);
3783cab2bb3Spatrick   CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
3793cab2bb3Spatrick   return res;
3803cab2bb3Spatrick }
3813cab2bb3Spatrick 
INTERCEPTOR(char *,strncat,char * dest,const char * src,SIZE_T n)3823cab2bb3Spatrick INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) {
3833cab2bb3Spatrick   ENSURE_MSAN_INITED();
3843cab2bb3Spatrick   GET_STORE_STACK_TRACE;
385*810390e3Srobert   SIZE_T dest_size = internal_strlen(dest);
386*810390e3Srobert   SIZE_T copy_size = internal_strnlen(src, n);
3873cab2bb3Spatrick   CHECK_UNPOISONED_STRING(dest + dest_size, 0);
3883cab2bb3Spatrick   char *res = REAL(strncat)(dest, src, n);
3893cab2bb3Spatrick   CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
3903cab2bb3Spatrick   __msan_unpoison(dest + dest_size + copy_size, 1); // \0
3913cab2bb3Spatrick   return res;
3923cab2bb3Spatrick }
3933cab2bb3Spatrick 
3943cab2bb3Spatrick // Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
3953cab2bb3Spatrick // deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
3963cab2bb3Spatrick #define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
3973cab2bb3Spatrick   ENSURE_MSAN_INITED();                             \
3983cab2bb3Spatrick   ret_type res = REAL(func)(__VA_ARGS__);           \
3993cab2bb3Spatrick   __msan_unpoison(endptr, sizeof(*endptr));         \
4003cab2bb3Spatrick   return res;
4013cab2bb3Spatrick 
4023cab2bb3Spatrick #define INTERCEPTOR_STRTO(ret_type, func, char_type)                       \
4033cab2bb3Spatrick   INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
4043cab2bb3Spatrick     INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr);                  \
4053cab2bb3Spatrick   }
4063cab2bb3Spatrick 
4073cab2bb3Spatrick #define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)                \
4083cab2bb3Spatrick   INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
4093cab2bb3Spatrick               int base) {                                                \
4103cab2bb3Spatrick     INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base);          \
4113cab2bb3Spatrick   }
4123cab2bb3Spatrick 
4133cab2bb3Spatrick #define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type)                 \
4143cab2bb3Spatrick   INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
4153cab2bb3Spatrick               void *loc) {                                               \
4163cab2bb3Spatrick     INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc);           \
4173cab2bb3Spatrick   }
4183cab2bb3Spatrick 
4193cab2bb3Spatrick #define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type)            \
4203cab2bb3Spatrick   INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
4213cab2bb3Spatrick               int base, void *loc) {                                     \
4223cab2bb3Spatrick     INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc);     \
4233cab2bb3Spatrick   }
4243cab2bb3Spatrick 
4253cab2bb3Spatrick #if SANITIZER_NETBSD
4263cab2bb3Spatrick #define INTERCEPTORS_STRTO(ret_type, func, char_type)      \
4273cab2bb3Spatrick   INTERCEPTOR_STRTO(ret_type, func, char_type)             \
4283cab2bb3Spatrick   INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type)
4293cab2bb3Spatrick 
4303cab2bb3Spatrick #define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type)      \
4313cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)             \
4323cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type)
4333cab2bb3Spatrick 
4343cab2bb3Spatrick #else
4353cab2bb3Spatrick #define INTERCEPTORS_STRTO(ret_type, func, char_type)      \
4363cab2bb3Spatrick   INTERCEPTOR_STRTO(ret_type, func, char_type)             \
4373cab2bb3Spatrick   INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type)     \
4383cab2bb3Spatrick   INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
4393cab2bb3Spatrick   INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
4403cab2bb3Spatrick 
4413cab2bb3Spatrick #define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type)      \
4423cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)             \
4433cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type)     \
4443cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
4453cab2bb3Spatrick   INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
4463cab2bb3Spatrick #endif
4473cab2bb3Spatrick 
INTERCEPTORS_STRTO(double,strtod,char)4483cab2bb3Spatrick INTERCEPTORS_STRTO(double, strtod, char)
4493cab2bb3Spatrick INTERCEPTORS_STRTO(float, strtof, char)
4503cab2bb3Spatrick INTERCEPTORS_STRTO(long double, strtold, char)
4513cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(long, strtol, char)
4523cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(long long, strtoll, char)
4533cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char)
4543cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char)
4553cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(u64, strtouq, char)
4563cab2bb3Spatrick 
4573cab2bb3Spatrick INTERCEPTORS_STRTO(double, wcstod, wchar_t)
4583cab2bb3Spatrick INTERCEPTORS_STRTO(float, wcstof, wchar_t)
4593cab2bb3Spatrick INTERCEPTORS_STRTO(long double, wcstold, wchar_t)
4603cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t)
4613cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t)
4623cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t)
4633cab2bb3Spatrick INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t)
4643cab2bb3Spatrick 
4653cab2bb3Spatrick #if SANITIZER_NETBSD
4663cab2bb3Spatrick #define INTERCEPT_STRTO(func) \
4673cab2bb3Spatrick   INTERCEPT_FUNCTION(func); \
4683cab2bb3Spatrick   INTERCEPT_FUNCTION(func##_l);
4693cab2bb3Spatrick #else
4703cab2bb3Spatrick #define INTERCEPT_STRTO(func) \
4713cab2bb3Spatrick   INTERCEPT_FUNCTION(func); \
4723cab2bb3Spatrick   INTERCEPT_FUNCTION(func##_l); \
4733cab2bb3Spatrick   INTERCEPT_FUNCTION(__##func##_l); \
4743cab2bb3Spatrick   INTERCEPT_FUNCTION(__##func##_internal);
4753cab2bb3Spatrick #endif
4763cab2bb3Spatrick 
4773cab2bb3Spatrick 
4783cab2bb3Spatrick // FIXME: support *wprintf in common format interceptors.
4793cab2bb3Spatrick INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
4803cab2bb3Spatrick   ENSURE_MSAN_INITED();
4813cab2bb3Spatrick   int res = REAL(vswprintf)(str, size, format, ap);
4823cab2bb3Spatrick   if (res >= 0) {
4833cab2bb3Spatrick     __msan_unpoison(str, 4 * (res + 1));
4843cab2bb3Spatrick   }
4853cab2bb3Spatrick   return res;
4863cab2bb3Spatrick }
4873cab2bb3Spatrick 
INTERCEPTOR(int,swprintf,void * str,uptr size,void * format,...)4883cab2bb3Spatrick INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
4893cab2bb3Spatrick   ENSURE_MSAN_INITED();
4903cab2bb3Spatrick   va_list ap;
4913cab2bb3Spatrick   va_start(ap, format);
4923cab2bb3Spatrick   int res = vswprintf(str, size, format, ap);
4933cab2bb3Spatrick   va_end(ap);
4943cab2bb3Spatrick   return res;
4953cab2bb3Spatrick }
4963cab2bb3Spatrick 
4973cab2bb3Spatrick #define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
4983cab2bb3Spatrick   ENSURE_MSAN_INITED();                                              \
4993cab2bb3Spatrick   InterceptorScope interceptor_scope;                                \
5003cab2bb3Spatrick   ret_type res = REAL(func)(s, __VA_ARGS__);                         \
5013cab2bb3Spatrick   if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1));          \
5023cab2bb3Spatrick   return res;
5033cab2bb3Spatrick 
INTERCEPTOR(SIZE_T,strftime,char * s,SIZE_T max,const char * format,__sanitizer_tm * tm)5043cab2bb3Spatrick INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
5053cab2bb3Spatrick             __sanitizer_tm *tm) {
5063cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
5073cab2bb3Spatrick }
5083cab2bb3Spatrick 
INTERCEPTOR(SIZE_T,strftime_l,char * s,SIZE_T max,const char * format,__sanitizer_tm * tm,void * loc)5093cab2bb3Spatrick INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
5103cab2bb3Spatrick             __sanitizer_tm *tm, void *loc) {
5113cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
5123cab2bb3Spatrick }
5133cab2bb3Spatrick 
5143cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(SIZE_T,__strftime_l,char * s,SIZE_T max,const char * format,__sanitizer_tm * tm,void * loc)5153cab2bb3Spatrick INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
5163cab2bb3Spatrick             __sanitizer_tm *tm, void *loc) {
5173cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
5183cab2bb3Spatrick                             loc);
5193cab2bb3Spatrick }
5203cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
5213cab2bb3Spatrick #else
5223cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___STRFTIME_L
5233cab2bb3Spatrick #endif
5243cab2bb3Spatrick 
INTERCEPTOR(SIZE_T,wcsftime,wchar_t * s,SIZE_T max,const wchar_t * format,__sanitizer_tm * tm)5253cab2bb3Spatrick INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
5263cab2bb3Spatrick             __sanitizer_tm *tm) {
5273cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
5283cab2bb3Spatrick }
5293cab2bb3Spatrick 
INTERCEPTOR(SIZE_T,wcsftime_l,wchar_t * s,SIZE_T max,const wchar_t * format,__sanitizer_tm * tm,void * loc)5303cab2bb3Spatrick INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
5313cab2bb3Spatrick             __sanitizer_tm *tm, void *loc) {
5323cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
5333cab2bb3Spatrick                             loc);
5343cab2bb3Spatrick }
5353cab2bb3Spatrick 
5363cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(SIZE_T,__wcsftime_l,wchar_t * s,SIZE_T max,const wchar_t * format,__sanitizer_tm * tm,void * loc)5373cab2bb3Spatrick INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
5383cab2bb3Spatrick             __sanitizer_tm *tm, void *loc) {
5393cab2bb3Spatrick   INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
5403cab2bb3Spatrick                             loc);
5413cab2bb3Spatrick }
5423cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
5433cab2bb3Spatrick #else
5443cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
5453cab2bb3Spatrick #endif
5463cab2bb3Spatrick 
INTERCEPTOR(int,mbtowc,wchar_t * dest,const char * src,SIZE_T n)5473cab2bb3Spatrick INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
5483cab2bb3Spatrick   ENSURE_MSAN_INITED();
5493cab2bb3Spatrick   int res = REAL(mbtowc)(dest, src, n);
5503cab2bb3Spatrick   if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
5513cab2bb3Spatrick   return res;
5523cab2bb3Spatrick }
5533cab2bb3Spatrick 
INTERCEPTOR(SIZE_T,mbrtowc,wchar_t * dest,const char * src,SIZE_T n,void * ps)5543cab2bb3Spatrick INTERCEPTOR(SIZE_T, mbrtowc, wchar_t *dest, const char *src, SIZE_T n,
5553cab2bb3Spatrick             void *ps) {
5563cab2bb3Spatrick   ENSURE_MSAN_INITED();
5573cab2bb3Spatrick   SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
5583cab2bb3Spatrick   if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
5593cab2bb3Spatrick   return res;
5603cab2bb3Spatrick }
5613cab2bb3Spatrick 
5623cab2bb3Spatrick // wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
INTERCEPTOR(wchar_t *,wmemcpy,wchar_t * dest,const wchar_t * src,SIZE_T n)5633cab2bb3Spatrick INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
5643cab2bb3Spatrick   ENSURE_MSAN_INITED();
5653cab2bb3Spatrick   GET_STORE_STACK_TRACE;
5663cab2bb3Spatrick   wchar_t *res = REAL(wmemcpy)(dest, src, n);
5673cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
5683cab2bb3Spatrick   return res;
5693cab2bb3Spatrick }
5703cab2bb3Spatrick 
5713cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(wchar_t *,wmempcpy,wchar_t * dest,const wchar_t * src,SIZE_T n)5723cab2bb3Spatrick INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
5733cab2bb3Spatrick   ENSURE_MSAN_INITED();
5743cab2bb3Spatrick   GET_STORE_STACK_TRACE;
5753cab2bb3Spatrick   wchar_t *res = REAL(wmempcpy)(dest, src, n);
5763cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
5773cab2bb3Spatrick   return res;
5783cab2bb3Spatrick }
5793cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_WMEMPCPY INTERCEPT_FUNCTION(wmempcpy)
5803cab2bb3Spatrick #else
5813cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_WMEMPCPY
5823cab2bb3Spatrick #endif
5833cab2bb3Spatrick 
INTERCEPTOR(wchar_t *,wmemset,wchar_t * s,wchar_t c,SIZE_T n)5843cab2bb3Spatrick INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
5853cab2bb3Spatrick   CHECK(MEM_IS_APP(s));
5863cab2bb3Spatrick   ENSURE_MSAN_INITED();
5873cab2bb3Spatrick   wchar_t *res = REAL(wmemset)(s, c, n);
5883cab2bb3Spatrick   __msan_unpoison(s, n * sizeof(wchar_t));
5893cab2bb3Spatrick   return res;
5903cab2bb3Spatrick }
5913cab2bb3Spatrick 
INTERCEPTOR(wchar_t *,wmemmove,wchar_t * dest,const wchar_t * src,SIZE_T n)5923cab2bb3Spatrick INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
5933cab2bb3Spatrick   ENSURE_MSAN_INITED();
5943cab2bb3Spatrick   GET_STORE_STACK_TRACE;
5953cab2bb3Spatrick   wchar_t *res = REAL(wmemmove)(dest, src, n);
5963cab2bb3Spatrick   MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
5973cab2bb3Spatrick   return res;
5983cab2bb3Spatrick }
5993cab2bb3Spatrick 
INTERCEPTOR(int,wcscmp,const wchar_t * s1,const wchar_t * s2)6003cab2bb3Spatrick INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
6013cab2bb3Spatrick   ENSURE_MSAN_INITED();
6023cab2bb3Spatrick   int res = REAL(wcscmp)(s1, s2);
6033cab2bb3Spatrick   return res;
6043cab2bb3Spatrick }
6053cab2bb3Spatrick 
INTERCEPTOR(int,gettimeofday,void * tv,void * tz)6063cab2bb3Spatrick INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
6073cab2bb3Spatrick   ENSURE_MSAN_INITED();
6083cab2bb3Spatrick   int res = REAL(gettimeofday)(tv, tz);
6093cab2bb3Spatrick   if (tv)
6103cab2bb3Spatrick     __msan_unpoison(tv, 16);
6113cab2bb3Spatrick   if (tz)
6123cab2bb3Spatrick     __msan_unpoison(tz, 8);
6133cab2bb3Spatrick   return res;
6143cab2bb3Spatrick }
6153cab2bb3Spatrick 
6163cab2bb3Spatrick #if !SANITIZER_NETBSD
INTERCEPTOR(char *,fcvt,double x,int a,int * b,int * c)6173cab2bb3Spatrick INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
6183cab2bb3Spatrick   ENSURE_MSAN_INITED();
6193cab2bb3Spatrick   char *res = REAL(fcvt)(x, a, b, c);
6203cab2bb3Spatrick   __msan_unpoison(b, sizeof(*b));
6213cab2bb3Spatrick   __msan_unpoison(c, sizeof(*c));
622*810390e3Srobert   if (res)
623*810390e3Srobert     __msan_unpoison(res, internal_strlen(res) + 1);
6243cab2bb3Spatrick   return res;
6253cab2bb3Spatrick }
6263cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FCVT INTERCEPT_FUNCTION(fcvt)
6273cab2bb3Spatrick #else
6283cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FCVT
6293cab2bb3Spatrick #endif
6303cab2bb3Spatrick 
INTERCEPTOR(char *,getenv,char * name)6313cab2bb3Spatrick INTERCEPTOR(char *, getenv, char *name) {
6323cab2bb3Spatrick   if (msan_init_is_running)
6333cab2bb3Spatrick     return REAL(getenv)(name);
6343cab2bb3Spatrick   ENSURE_MSAN_INITED();
6353cab2bb3Spatrick   char *res = REAL(getenv)(name);
636*810390e3Srobert   if (res)
637*810390e3Srobert     __msan_unpoison(res, internal_strlen(res) + 1);
6383cab2bb3Spatrick   return res;
6393cab2bb3Spatrick }
6403cab2bb3Spatrick 
6413cab2bb3Spatrick extern char **environ;
6423cab2bb3Spatrick 
UnpoisonEnviron()6433cab2bb3Spatrick static void UnpoisonEnviron() {
6443cab2bb3Spatrick   char **envp = environ;
6453cab2bb3Spatrick   for (; *envp; ++envp) {
6463cab2bb3Spatrick     __msan_unpoison(envp, sizeof(*envp));
647*810390e3Srobert     __msan_unpoison(*envp, internal_strlen(*envp) + 1);
6483cab2bb3Spatrick   }
6493cab2bb3Spatrick   // Trailing NULL pointer.
6503cab2bb3Spatrick   __msan_unpoison(envp, sizeof(*envp));
6513cab2bb3Spatrick }
6523cab2bb3Spatrick 
INTERCEPTOR(int,setenv,const char * name,const char * value,int overwrite)6533cab2bb3Spatrick INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
6543cab2bb3Spatrick   ENSURE_MSAN_INITED();
6553cab2bb3Spatrick   CHECK_UNPOISONED_STRING(name, 0);
6563cab2bb3Spatrick   int res = REAL(setenv)(name, value, overwrite);
6573cab2bb3Spatrick   if (!res) UnpoisonEnviron();
6583cab2bb3Spatrick   return res;
6593cab2bb3Spatrick }
6603cab2bb3Spatrick 
INTERCEPTOR(int,putenv,char * string)6613cab2bb3Spatrick INTERCEPTOR(int, putenv, char *string) {
6623cab2bb3Spatrick   ENSURE_MSAN_INITED();
6633cab2bb3Spatrick   int res = REAL(putenv)(string);
6643cab2bb3Spatrick   if (!res) UnpoisonEnviron();
6653cab2bb3Spatrick   return res;
6663cab2bb3Spatrick }
6673cab2bb3Spatrick 
668*810390e3Srobert #define SANITIZER_STAT_LINUX (SANITIZER_LINUX && __GLIBC_PREREQ(2, 33))
669*810390e3Srobert #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX
INTERCEPTOR(int,fstat,int fd,void * buf)6703cab2bb3Spatrick INTERCEPTOR(int, fstat, int fd, void *buf) {
6713cab2bb3Spatrick   ENSURE_MSAN_INITED();
6723cab2bb3Spatrick   int res = REAL(fstat)(fd, buf);
6733cab2bb3Spatrick   if (!res)
6743cab2bb3Spatrick     __msan_unpoison(buf, __sanitizer::struct_stat_sz);
6753cab2bb3Spatrick   return res;
6763cab2bb3Spatrick }
677*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTAT MSAN_INTERCEPT_FUNC(fstat)
6783cab2bb3Spatrick #else
6793cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FSTAT
6803cab2bb3Spatrick #endif
6813cab2bb3Spatrick 
682*810390e3Srobert #if SANITIZER_STAT_LINUX
INTERCEPTOR(int,fstat64,int fd,void * buf)683*810390e3Srobert INTERCEPTOR(int, fstat64, int fd, void *buf) {
684*810390e3Srobert   ENSURE_MSAN_INITED();
685*810390e3Srobert   int res = REAL(fstat64)(fd, buf);
686*810390e3Srobert   if (!res)
687*810390e3Srobert     __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
688*810390e3Srobert   return res;
689*810390e3Srobert }
690*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTAT64 MSAN_INTERCEPT_FUNC(fstat64)
691*810390e3Srobert #else
692*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTAT64
693*810390e3Srobert #endif
694*810390e3Srobert 
695*810390e3Srobert #if SANITIZER_GLIBC
INTERCEPTOR(int,__fxstat,int magic,int fd,void * buf)6963cab2bb3Spatrick INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
6973cab2bb3Spatrick   ENSURE_MSAN_INITED();
6983cab2bb3Spatrick   int res = REAL(__fxstat)(magic, fd, buf);
6993cab2bb3Spatrick   if (!res)
7003cab2bb3Spatrick     __msan_unpoison(buf, __sanitizer::struct_stat_sz);
7013cab2bb3Spatrick   return res;
7023cab2bb3Spatrick }
703*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT___FXSTAT MSAN_INTERCEPT_FUNC(__fxstat)
7043cab2bb3Spatrick #else
7053cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___FXSTAT
7063cab2bb3Spatrick #endif
7073cab2bb3Spatrick 
708*810390e3Srobert #if SANITIZER_GLIBC
INTERCEPTOR(int,__fxstat64,int magic,int fd,void * buf)7093cab2bb3Spatrick INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
7103cab2bb3Spatrick   ENSURE_MSAN_INITED();
7113cab2bb3Spatrick   int res = REAL(__fxstat64)(magic, fd, buf);
7123cab2bb3Spatrick   if (!res)
7133cab2bb3Spatrick     __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
7143cab2bb3Spatrick   return res;
7153cab2bb3Spatrick }
716*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT___FXSTAT64 MSAN_INTERCEPT_FUNC(__fxstat64)
7173cab2bb3Spatrick #else
7183cab2bb3Spatrick #  define MSAN_MAYBE_INTERCEPT___FXSTAT64
7193cab2bb3Spatrick #endif
7203cab2bb3Spatrick 
721*810390e3Srobert #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX
INTERCEPTOR(int,fstatat,int fd,char * pathname,void * buf,int flags)7223cab2bb3Spatrick INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) {
7233cab2bb3Spatrick   ENSURE_MSAN_INITED();
7243cab2bb3Spatrick   int res = REAL(fstatat)(fd, pathname, buf, flags);
7253cab2bb3Spatrick   if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
7263cab2bb3Spatrick   return res;
7273cab2bb3Spatrick }
728*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTATAT MSAN_INTERCEPT_FUNC(fstatat)
7293cab2bb3Spatrick #else
730*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTATAT
731*810390e3Srobert #endif
732*810390e3Srobert 
733*810390e3Srobert #if SANITIZER_STAT_LINUX
INTERCEPTOR(int,fstatat64,int fd,char * pathname,void * buf,int flags)734*810390e3Srobert INTERCEPTOR(int, fstatat64, int fd, char *pathname, void *buf, int flags) {
735*810390e3Srobert   ENSURE_MSAN_INITED();
736*810390e3Srobert   int res = REAL(fstatat64)(fd, pathname, buf, flags);
737*810390e3Srobert   if (!res)
738*810390e3Srobert     __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
739*810390e3Srobert   return res;
740*810390e3Srobert }
741*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTATAT64 MSAN_INTERCEPT_FUNC(fstatat64)
742*810390e3Srobert #else
743*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT_FSTATAT64
744*810390e3Srobert #endif
745*810390e3Srobert 
746*810390e3Srobert #if SANITIZER_GLIBC
INTERCEPTOR(int,__fxstatat,int magic,int fd,char * pathname,void * buf,int flags)7473cab2bb3Spatrick INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
7483cab2bb3Spatrick             int flags) {
7493cab2bb3Spatrick   ENSURE_MSAN_INITED();
7503cab2bb3Spatrick   int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
7513cab2bb3Spatrick   if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
7523cab2bb3Spatrick   return res;
7533cab2bb3Spatrick }
754*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT___FXSTATAT MSAN_INTERCEPT_FUNC(__fxstatat)
755*810390e3Srobert #else
756*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT___FXSTATAT
7573cab2bb3Spatrick #endif
7583cab2bb3Spatrick 
759*810390e3Srobert #if SANITIZER_GLIBC
INTERCEPTOR(int,__fxstatat64,int magic,int fd,char * pathname,void * buf,int flags)7603cab2bb3Spatrick INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
7613cab2bb3Spatrick             int flags) {
7623cab2bb3Spatrick   ENSURE_MSAN_INITED();
7633cab2bb3Spatrick   int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
7643cab2bb3Spatrick   if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
7653cab2bb3Spatrick   return res;
7663cab2bb3Spatrick }
767*810390e3Srobert #  define MSAN_MAYBE_INTERCEPT___FXSTATAT64 MSAN_INTERCEPT_FUNC(__fxstatat64)
7683cab2bb3Spatrick #else
7693cab2bb3Spatrick #  define MSAN_MAYBE_INTERCEPT___FXSTATAT64
7703cab2bb3Spatrick #endif
7713cab2bb3Spatrick 
INTERCEPTOR(int,pipe,int pipefd[2])7723cab2bb3Spatrick INTERCEPTOR(int, pipe, int pipefd[2]) {
7733cab2bb3Spatrick   if (msan_init_is_running)
7743cab2bb3Spatrick     return REAL(pipe)(pipefd);
7753cab2bb3Spatrick   ENSURE_MSAN_INITED();
7763cab2bb3Spatrick   int res = REAL(pipe)(pipefd);
7773cab2bb3Spatrick   if (!res)
7783cab2bb3Spatrick     __msan_unpoison(pipefd, sizeof(int[2]));
7793cab2bb3Spatrick   return res;
7803cab2bb3Spatrick }
7813cab2bb3Spatrick 
INTERCEPTOR(int,pipe2,int pipefd[2],int flags)7823cab2bb3Spatrick INTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
7833cab2bb3Spatrick   ENSURE_MSAN_INITED();
7843cab2bb3Spatrick   int res = REAL(pipe2)(pipefd, flags);
7853cab2bb3Spatrick   if (!res)
7863cab2bb3Spatrick     __msan_unpoison(pipefd, sizeof(int[2]));
7873cab2bb3Spatrick   return res;
7883cab2bb3Spatrick }
7893cab2bb3Spatrick 
INTERCEPTOR(int,socketpair,int domain,int type,int protocol,int sv[2])7903cab2bb3Spatrick INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
7913cab2bb3Spatrick   ENSURE_MSAN_INITED();
7923cab2bb3Spatrick   int res = REAL(socketpair)(domain, type, protocol, sv);
7933cab2bb3Spatrick   if (!res)
7943cab2bb3Spatrick     __msan_unpoison(sv, sizeof(int[2]));
7953cab2bb3Spatrick   return res;
7963cab2bb3Spatrick }
7973cab2bb3Spatrick 
7983cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(char *,fgets_unlocked,char * s,int size,void * stream)7993cab2bb3Spatrick INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
8003cab2bb3Spatrick   ENSURE_MSAN_INITED();
8013cab2bb3Spatrick   char *res = REAL(fgets_unlocked)(s, size, stream);
8023cab2bb3Spatrick   if (res)
803*810390e3Srobert     __msan_unpoison(s, internal_strlen(s) + 1);
8043cab2bb3Spatrick   return res;
8053cab2bb3Spatrick }
8063cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
8073cab2bb3Spatrick #else
8083cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
8093cab2bb3Spatrick #endif
8103cab2bb3Spatrick 
8113cab2bb3Spatrick #define INTERCEPTOR_GETRLIMIT_BODY(func, resource, rlim)  \
8123cab2bb3Spatrick   if (msan_init_is_running)                               \
8133cab2bb3Spatrick     return REAL(getrlimit)(resource, rlim);               \
8143cab2bb3Spatrick   ENSURE_MSAN_INITED();                                   \
8153cab2bb3Spatrick   int res = REAL(func)(resource, rlim);                   \
8163cab2bb3Spatrick   if (!res)                                               \
8173cab2bb3Spatrick     __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz); \
8183cab2bb3Spatrick   return res
8193cab2bb3Spatrick 
INTERCEPTOR(int,getrlimit,int resource,void * rlim)8203cab2bb3Spatrick INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
8213cab2bb3Spatrick   INTERCEPTOR_GETRLIMIT_BODY(getrlimit, resource, rlim);
8223cab2bb3Spatrick }
8233cab2bb3Spatrick 
8243cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(int,__getrlimit,int resource,void * rlim)8253cab2bb3Spatrick INTERCEPTOR(int, __getrlimit, int resource, void *rlim) {
8263cab2bb3Spatrick   INTERCEPTOR_GETRLIMIT_BODY(__getrlimit, resource, rlim);
8273cab2bb3Spatrick }
8283cab2bb3Spatrick 
INTERCEPTOR(int,getrlimit64,int resource,void * rlim)8293cab2bb3Spatrick INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
8303cab2bb3Spatrick   if (msan_init_is_running) return REAL(getrlimit64)(resource, rlim);
8313cab2bb3Spatrick   ENSURE_MSAN_INITED();
8323cab2bb3Spatrick   int res = REAL(getrlimit64)(resource, rlim);
8333cab2bb3Spatrick   if (!res) __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
8343cab2bb3Spatrick   return res;
8353cab2bb3Spatrick }
8363cab2bb3Spatrick 
INTERCEPTOR(int,prlimit,int pid,int resource,void * new_rlimit,void * old_rlimit)8373cab2bb3Spatrick INTERCEPTOR(int, prlimit, int pid, int resource, void *new_rlimit,
8383cab2bb3Spatrick             void *old_rlimit) {
8393cab2bb3Spatrick   if (msan_init_is_running)
8403cab2bb3Spatrick     return REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
8413cab2bb3Spatrick   ENSURE_MSAN_INITED();
8423cab2bb3Spatrick   CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit_sz);
8433cab2bb3Spatrick   int res = REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
8443cab2bb3Spatrick   if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit_sz);
8453cab2bb3Spatrick   return res;
8463cab2bb3Spatrick }
8473cab2bb3Spatrick 
INTERCEPTOR(int,prlimit64,int pid,int resource,void * new_rlimit,void * old_rlimit)8483cab2bb3Spatrick INTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit,
8493cab2bb3Spatrick             void *old_rlimit) {
8503cab2bb3Spatrick   if (msan_init_is_running)
8513cab2bb3Spatrick     return REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
8523cab2bb3Spatrick   ENSURE_MSAN_INITED();
8533cab2bb3Spatrick   CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit64_sz);
8543cab2bb3Spatrick   int res = REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
8553cab2bb3Spatrick   if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit64_sz);
8563cab2bb3Spatrick   return res;
8573cab2bb3Spatrick }
8583cab2bb3Spatrick 
8593cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___GETRLIMIT INTERCEPT_FUNCTION(__getrlimit)
8603cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
8613cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PRLIMIT INTERCEPT_FUNCTION(prlimit)
8623cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PRLIMIT64 INTERCEPT_FUNCTION(prlimit64)
8633cab2bb3Spatrick #else
8643cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT___GETRLIMIT
8653cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
8663cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PRLIMIT
8673cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_PRLIMIT64
8683cab2bb3Spatrick #endif
8693cab2bb3Spatrick 
INTERCEPTOR(int,gethostname,char * name,SIZE_T len)8703cab2bb3Spatrick INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
8713cab2bb3Spatrick   ENSURE_MSAN_INITED();
8723cab2bb3Spatrick   int res = REAL(gethostname)(name, len);
873d89ec533Spatrick   if (!res || (res == -1 && errno == errno_ENAMETOOLONG)) {
874*810390e3Srobert     SIZE_T real_len = internal_strnlen(name, len);
8753cab2bb3Spatrick     if (real_len < len)
8763cab2bb3Spatrick       ++real_len;
8773cab2bb3Spatrick     __msan_unpoison(name, real_len);
8783cab2bb3Spatrick   }
8793cab2bb3Spatrick   return res;
8803cab2bb3Spatrick }
8813cab2bb3Spatrick 
8823cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(int,epoll_wait,int epfd,void * events,int maxevents,int timeout)8833cab2bb3Spatrick INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
8843cab2bb3Spatrick     int timeout) {
8853cab2bb3Spatrick   ENSURE_MSAN_INITED();
8863cab2bb3Spatrick   int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
8873cab2bb3Spatrick   if (res > 0) {
8883cab2bb3Spatrick     __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
8893cab2bb3Spatrick   }
8903cab2bb3Spatrick   return res;
8913cab2bb3Spatrick }
8923cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
8933cab2bb3Spatrick #else
8943cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
8953cab2bb3Spatrick #endif
8963cab2bb3Spatrick 
8973cab2bb3Spatrick #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(int,epoll_pwait,int epfd,void * events,int maxevents,int timeout,void * sigmask)8983cab2bb3Spatrick INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
8993cab2bb3Spatrick     int timeout, void *sigmask) {
9003cab2bb3Spatrick   ENSURE_MSAN_INITED();
9013cab2bb3Spatrick   int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
9023cab2bb3Spatrick   if (res > 0) {
9033cab2bb3Spatrick     __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
9043cab2bb3Spatrick   }
9053cab2bb3Spatrick   return res;
9063cab2bb3Spatrick }
9073cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
9083cab2bb3Spatrick #else
9093cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
9103cab2bb3Spatrick #endif
9113cab2bb3Spatrick 
INTERCEPTOR(void *,calloc,SIZE_T nmemb,SIZE_T size)9123cab2bb3Spatrick INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
9133cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
914*810390e3Srobert   if (DlsymAlloc::Use())
915*810390e3Srobert     return DlsymAlloc::Callocate(nmemb, size);
9163cab2bb3Spatrick   return msan_calloc(nmemb, size, &stack);
9173cab2bb3Spatrick }
9183cab2bb3Spatrick 
INTERCEPTOR(void *,realloc,void * ptr,SIZE_T size)9193cab2bb3Spatrick INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
920*810390e3Srobert   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
921*810390e3Srobert     return DlsymAlloc::Realloc(ptr, size);
9223cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
9233cab2bb3Spatrick   return msan_realloc(ptr, size, &stack);
9243cab2bb3Spatrick }
9253cab2bb3Spatrick 
INTERCEPTOR(void *,reallocarray,void * ptr,SIZE_T nmemb,SIZE_T size)9263cab2bb3Spatrick INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) {
9273cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
9283cab2bb3Spatrick   return msan_reallocarray(ptr, nmemb, size, &stack);
9293cab2bb3Spatrick }
9303cab2bb3Spatrick 
INTERCEPTOR(void *,malloc,SIZE_T size)9313cab2bb3Spatrick INTERCEPTOR(void *, malloc, SIZE_T size) {
932*810390e3Srobert   if (DlsymAlloc::Use())
933*810390e3Srobert     return DlsymAlloc::Allocate(size);
9343cab2bb3Spatrick   GET_MALLOC_STACK_TRACE;
9353cab2bb3Spatrick   return msan_malloc(size, &stack);
9363cab2bb3Spatrick }
9373cab2bb3Spatrick 
__msan_allocated_memory(const void * data,uptr size)9383cab2bb3Spatrick void __msan_allocated_memory(const void *data, uptr size) {
9393cab2bb3Spatrick   if (flags()->poison_in_malloc) {
940*810390e3Srobert     GET_MALLOC_STACK_TRACE;
9413cab2bb3Spatrick     stack.tag = STACK_TRACE_TAG_POISON;
9423cab2bb3Spatrick     PoisonMemory(data, size, &stack);
9433cab2bb3Spatrick   }
9443cab2bb3Spatrick }
9453cab2bb3Spatrick 
__msan_copy_shadow(void * dest,const void * src,uptr n)9463cab2bb3Spatrick void __msan_copy_shadow(void *dest, const void *src, uptr n) {
9473cab2bb3Spatrick   GET_STORE_STACK_TRACE;
9483cab2bb3Spatrick   MoveShadowAndOrigin(dest, src, n, &stack);
9493cab2bb3Spatrick }
9503cab2bb3Spatrick 
__sanitizer_dtor_callback(const void * data,uptr size)9513cab2bb3Spatrick void __sanitizer_dtor_callback(const void *data, uptr size) {
9523cab2bb3Spatrick   if (flags()->poison_in_dtor) {
953*810390e3Srobert     GET_MALLOC_STACK_TRACE;
9543cab2bb3Spatrick     stack.tag = STACK_TRACE_TAG_POISON;
9553cab2bb3Spatrick     PoisonMemory(data, size, &stack);
9563cab2bb3Spatrick   }
9573cab2bb3Spatrick }
9583cab2bb3Spatrick 
__sanitizer_dtor_callback_fields(const void * data,uptr size)959*810390e3Srobert void __sanitizer_dtor_callback_fields(const void *data, uptr size) {
960*810390e3Srobert   if (flags()->poison_in_dtor) {
961*810390e3Srobert     GET_MALLOC_STACK_TRACE;
962*810390e3Srobert     stack.tag = STACK_TRACE_TAG_FIELDS;
963*810390e3Srobert     PoisonMemory(data, size, &stack);
964*810390e3Srobert   }
965*810390e3Srobert }
966*810390e3Srobert 
__sanitizer_dtor_callback_vptr(const void * data)967*810390e3Srobert void __sanitizer_dtor_callback_vptr(const void *data) {
968*810390e3Srobert   if (flags()->poison_in_dtor) {
969*810390e3Srobert     GET_MALLOC_STACK_TRACE;
970*810390e3Srobert     stack.tag = STACK_TRACE_TAG_VPTR;
971*810390e3Srobert     PoisonMemory(data, sizeof(void *), &stack);
972*810390e3Srobert   }
973*810390e3Srobert }
974*810390e3Srobert 
9753cab2bb3Spatrick template <class Mmap>
mmap_interceptor(Mmap real_mmap,void * addr,SIZE_T length,int prot,int flags,int fd,OFF64_T offset)9763cab2bb3Spatrick static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
9773cab2bb3Spatrick                               int prot, int flags, int fd, OFF64_T offset) {
9781f9cb04fSpatrick   SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
9791f9cb04fSpatrick   void *end_addr = (char *)addr + (rounded_length - 1);
9801f9cb04fSpatrick   if (addr && (!MEM_IS_APP(addr) || !MEM_IS_APP(end_addr))) {
9813cab2bb3Spatrick     if (flags & map_fixed) {
9823cab2bb3Spatrick       errno = errno_EINVAL;
9833cab2bb3Spatrick       return (void *)-1;
9843cab2bb3Spatrick     } else {
9853cab2bb3Spatrick       addr = nullptr;
9863cab2bb3Spatrick     }
9873cab2bb3Spatrick   }
9883cab2bb3Spatrick   void *res = real_mmap(addr, length, prot, flags, fd, offset);
9891f9cb04fSpatrick   if (res != (void *)-1) {
9901f9cb04fSpatrick     void *end_res = (char *)res + (rounded_length - 1);
9911f9cb04fSpatrick     if (MEM_IS_APP(res) && MEM_IS_APP(end_res)) {
9921f9cb04fSpatrick       __msan_unpoison(res, rounded_length);
9931f9cb04fSpatrick     } else {
9941f9cb04fSpatrick       // Application has attempted to map more memory than is supported by
9951f9cb04fSpatrick       // MSAN. Act as if we ran out of memory.
9961f9cb04fSpatrick       internal_munmap(res, length);
9971f9cb04fSpatrick       errno = errno_ENOMEM;
9981f9cb04fSpatrick       return (void *)-1;
9991f9cb04fSpatrick     }
10001f9cb04fSpatrick   }
10013cab2bb3Spatrick   return res;
10023cab2bb3Spatrick }
10033cab2bb3Spatrick 
INTERCEPTOR(int,getrusage,int who,void * usage)10043cab2bb3Spatrick INTERCEPTOR(int, getrusage, int who, void *usage) {
10053cab2bb3Spatrick   ENSURE_MSAN_INITED();
10063cab2bb3Spatrick   int res = REAL(getrusage)(who, usage);
10073cab2bb3Spatrick   if (res == 0) {
10083cab2bb3Spatrick     __msan_unpoison(usage, __sanitizer::struct_rusage_sz);
10093cab2bb3Spatrick   }
10103cab2bb3Spatrick   return res;
10113cab2bb3Spatrick }
10123cab2bb3Spatrick 
10133cab2bb3Spatrick class SignalHandlerScope {
10143cab2bb3Spatrick  public:
SignalHandlerScope()10153cab2bb3Spatrick   SignalHandlerScope() {
10163cab2bb3Spatrick     if (MsanThread *t = GetCurrentThread())
10173cab2bb3Spatrick       t->EnterSignalHandler();
10183cab2bb3Spatrick   }
~SignalHandlerScope()10193cab2bb3Spatrick   ~SignalHandlerScope() {
10203cab2bb3Spatrick     if (MsanThread *t = GetCurrentThread())
10213cab2bb3Spatrick       t->LeaveSignalHandler();
10223cab2bb3Spatrick   }
10233cab2bb3Spatrick };
10243cab2bb3Spatrick 
10253cab2bb3Spatrick // sigactions_mu guarantees atomicity of sigaction() and signal() calls.
10263cab2bb3Spatrick // Access to sigactions[] is gone with relaxed atomics to avoid data race with
10273cab2bb3Spatrick // the signal handler.
10283cab2bb3Spatrick const int kMaxSignals = 1024;
10293cab2bb3Spatrick static atomic_uintptr_t sigactions[kMaxSignals];
10303cab2bb3Spatrick static StaticSpinMutex sigactions_mu;
10313cab2bb3Spatrick 
SignalHandler(int signo)10323cab2bb3Spatrick static void SignalHandler(int signo) {
10333cab2bb3Spatrick   SignalHandlerScope signal_handler_scope;
10343cab2bb3Spatrick   ScopedThreadLocalStateBackup stlsb;
10353cab2bb3Spatrick   UnpoisonParam(1);
10363cab2bb3Spatrick 
10373cab2bb3Spatrick   typedef void (*signal_cb)(int x);
10383cab2bb3Spatrick   signal_cb cb =
10393cab2bb3Spatrick       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
10403cab2bb3Spatrick   cb(signo);
10413cab2bb3Spatrick }
10423cab2bb3Spatrick 
SignalAction(int signo,void * si,void * uc)10433cab2bb3Spatrick static void SignalAction(int signo, void *si, void *uc) {
10443cab2bb3Spatrick   SignalHandlerScope signal_handler_scope;
10453cab2bb3Spatrick   ScopedThreadLocalStateBackup stlsb;
10463cab2bb3Spatrick   UnpoisonParam(3);
10473cab2bb3Spatrick   __msan_unpoison(si, sizeof(__sanitizer_sigaction));
1048*810390e3Srobert   __msan_unpoison(uc, ucontext_t_sz(uc));
10493cab2bb3Spatrick 
10503cab2bb3Spatrick   typedef void (*sigaction_cb)(int, void *, void *);
10513cab2bb3Spatrick   sigaction_cb cb =
10523cab2bb3Spatrick       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
10533cab2bb3Spatrick   cb(signo, si, uc);
1054*810390e3Srobert   CHECK_UNPOISONED(uc, ucontext_t_sz(uc));
10553cab2bb3Spatrick }
10563cab2bb3Spatrick 
read_sigaction(const __sanitizer_sigaction * act)10573cab2bb3Spatrick static void read_sigaction(const __sanitizer_sigaction *act) {
10583cab2bb3Spatrick   CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags));
10593cab2bb3Spatrick   if (act->sa_flags & __sanitizer::sa_siginfo)
10603cab2bb3Spatrick     CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction));
10613cab2bb3Spatrick   else
10623cab2bb3Spatrick     CHECK_UNPOISONED(&act->handler, sizeof(act->handler));
10633cab2bb3Spatrick   CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask));
10643cab2bb3Spatrick }
10653cab2bb3Spatrick 
10663cab2bb3Spatrick extern "C" int pthread_attr_init(void *attr);
10673cab2bb3Spatrick extern "C" int pthread_attr_destroy(void *attr);
10683cab2bb3Spatrick 
MsanThreadStartFunc(void * arg)10693cab2bb3Spatrick static void *MsanThreadStartFunc(void *arg) {
10703cab2bb3Spatrick   MsanThread *t = (MsanThread *)arg;
10713cab2bb3Spatrick   SetCurrentThread(t);
1072*810390e3Srobert   t->Init();
1073*810390e3Srobert   SetSigProcMask(&t->starting_sigset_, nullptr);
10743cab2bb3Spatrick   return t->ThreadStart();
10753cab2bb3Spatrick }
10763cab2bb3Spatrick 
INTERCEPTOR(int,pthread_create,void * th,void * attr,void * (* callback)(void *),void * param)10773cab2bb3Spatrick INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
10783cab2bb3Spatrick             void * param) {
10793cab2bb3Spatrick   ENSURE_MSAN_INITED(); // for GetTlsSize()
10803cab2bb3Spatrick   __sanitizer_pthread_attr_t myattr;
10813cab2bb3Spatrick   if (!attr) {
10823cab2bb3Spatrick     pthread_attr_init(&myattr);
10833cab2bb3Spatrick     attr = &myattr;
10843cab2bb3Spatrick   }
10853cab2bb3Spatrick 
10863cab2bb3Spatrick   AdjustStackSize(attr);
10873cab2bb3Spatrick 
10883cab2bb3Spatrick   MsanThread *t = MsanThread::Create(callback, param);
1089*810390e3Srobert   ScopedBlockSignals block(&t->starting_sigset_);
10903cab2bb3Spatrick   int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
10913cab2bb3Spatrick 
10923cab2bb3Spatrick   if (attr == &myattr)
10933cab2bb3Spatrick     pthread_attr_destroy(&myattr);
10943cab2bb3Spatrick   if (!res) {
10953cab2bb3Spatrick     __msan_unpoison(th, __sanitizer::pthread_t_sz);
10963cab2bb3Spatrick   }
10973cab2bb3Spatrick   return res;
10983cab2bb3Spatrick }
10993cab2bb3Spatrick 
INTERCEPTOR(int,pthread_key_create,__sanitizer_pthread_key_t * key,void (* dtor)(void * value))11003cab2bb3Spatrick INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
11013cab2bb3Spatrick             void (*dtor)(void *value)) {
11023cab2bb3Spatrick   if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
11033cab2bb3Spatrick   ENSURE_MSAN_INITED();
11043cab2bb3Spatrick   int res = REAL(pthread_key_create)(key, dtor);
11053cab2bb3Spatrick   if (!res && key)
11063cab2bb3Spatrick     __msan_unpoison(key, sizeof(*key));
11073cab2bb3Spatrick   return res;
11083cab2bb3Spatrick }
11093cab2bb3Spatrick 
11103cab2bb3Spatrick #if SANITIZER_NETBSD
11113cab2bb3Spatrick INTERCEPTOR(int, __libc_thr_keycreate, __sanitizer_pthread_key_t *m,
11123cab2bb3Spatrick             void (*dtor)(void *value))
11133cab2bb3Spatrick ALIAS(WRAPPER_NAME(pthread_key_create));
11143cab2bb3Spatrick #endif
11153cab2bb3Spatrick 
INTERCEPTOR(int,pthread_join,void * th,void ** retval)11163cab2bb3Spatrick INTERCEPTOR(int, pthread_join, void *th, void **retval) {
11173cab2bb3Spatrick   ENSURE_MSAN_INITED();
11183cab2bb3Spatrick   int res = REAL(pthread_join)(th, retval);
11193cab2bb3Spatrick   if (!res && retval)
11203cab2bb3Spatrick     __msan_unpoison(retval, sizeof(*retval));
11213cab2bb3Spatrick   return res;
11223cab2bb3Spatrick }
11233cab2bb3Spatrick 
1124*810390e3Srobert DEFINE_REAL_PTHREAD_FUNCTIONS
1125*810390e3Srobert 
11263cab2bb3Spatrick extern char *tzname[2];
11273cab2bb3Spatrick 
INTERCEPTOR(void,tzset,int fake)11283cab2bb3Spatrick INTERCEPTOR(void, tzset, int fake) {
11293cab2bb3Spatrick   ENSURE_MSAN_INITED();
11303cab2bb3Spatrick   InterceptorScope interceptor_scope;
11313cab2bb3Spatrick   REAL(tzset)(fake);
11323cab2bb3Spatrick   if (tzname[0])
1133*810390e3Srobert     __msan_unpoison(tzname[0], internal_strlen(tzname[0]) + 1);
11343cab2bb3Spatrick   if (tzname[1])
1135*810390e3Srobert     __msan_unpoison(tzname[1], internal_strlen(tzname[1]) + 1);
11363cab2bb3Spatrick   return;
11373cab2bb3Spatrick }
11383cab2bb3Spatrick 
11393cab2bb3Spatrick struct MSanAtExitRecord {
11403cab2bb3Spatrick   void (*func)(void *arg);
11413cab2bb3Spatrick   void *arg;
11423cab2bb3Spatrick };
11433cab2bb3Spatrick 
11443cab2bb3Spatrick struct InterceptorContext {
1145*810390e3Srobert   Mutex atexit_mu;
11463cab2bb3Spatrick   Vector<struct MSanAtExitRecord *> AtExitStack;
11473cab2bb3Spatrick 
InterceptorContextInterceptorContext11483cab2bb3Spatrick   InterceptorContext()
11493cab2bb3Spatrick       : AtExitStack() {
11503cab2bb3Spatrick   }
11513cab2bb3Spatrick };
11523cab2bb3Spatrick 
11533cab2bb3Spatrick static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
interceptor_ctx()11543cab2bb3Spatrick InterceptorContext *interceptor_ctx() {
11553cab2bb3Spatrick   return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
11563cab2bb3Spatrick }
11573cab2bb3Spatrick 
MSanAtExitWrapper()11583cab2bb3Spatrick void MSanAtExitWrapper() {
11593cab2bb3Spatrick   MSanAtExitRecord *r;
11603cab2bb3Spatrick   {
1161*810390e3Srobert     Lock l(&interceptor_ctx()->atexit_mu);
11623cab2bb3Spatrick 
11633cab2bb3Spatrick     uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
11643cab2bb3Spatrick     r = interceptor_ctx()->AtExitStack[element];
11653cab2bb3Spatrick     interceptor_ctx()->AtExitStack.PopBack();
11663cab2bb3Spatrick   }
11673cab2bb3Spatrick 
11683cab2bb3Spatrick   UnpoisonParam(1);
11693cab2bb3Spatrick   ((void(*)())r->func)();
11703cab2bb3Spatrick   InternalFree(r);
11713cab2bb3Spatrick }
11723cab2bb3Spatrick 
MSanCxaAtExitWrapper(void * arg)11733cab2bb3Spatrick void MSanCxaAtExitWrapper(void *arg) {
11743cab2bb3Spatrick   UnpoisonParam(1);
11753cab2bb3Spatrick   MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
11763cab2bb3Spatrick   // libc before 2.27 had race which caused occasional double handler execution
11773cab2bb3Spatrick   // https://sourceware.org/ml/libc-alpha/2017-08/msg01204.html
11783cab2bb3Spatrick   if (!r->func)
11793cab2bb3Spatrick     return;
11803cab2bb3Spatrick   r->func(r->arg);
11813cab2bb3Spatrick   r->func = nullptr;
11823cab2bb3Spatrick }
11833cab2bb3Spatrick 
11843cab2bb3Spatrick static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso);
11853cab2bb3Spatrick 
11863cab2bb3Spatrick // Unpoison argument shadow for C++ module destructors.
INTERCEPTOR(int,__cxa_atexit,void (* func)(void *),void * arg,void * dso_handle)11873cab2bb3Spatrick INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
11883cab2bb3Spatrick             void *dso_handle) {
11893cab2bb3Spatrick   if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
11903cab2bb3Spatrick   return setup_at_exit_wrapper((void(*)())func, arg, dso_handle);
11913cab2bb3Spatrick }
11923cab2bb3Spatrick 
11933cab2bb3Spatrick // Unpoison argument shadow for C++ module destructors.
INTERCEPTOR(int,atexit,void (* func)())11943cab2bb3Spatrick INTERCEPTOR(int, atexit, void (*func)()) {
1195*810390e3Srobert   // Avoid calling real atexit as it is unreachable on at least on Linux.
11963cab2bb3Spatrick   if (msan_init_is_running)
11973cab2bb3Spatrick     return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0);
11983cab2bb3Spatrick   return setup_at_exit_wrapper((void(*)())func, 0, 0);
11993cab2bb3Spatrick }
12003cab2bb3Spatrick 
setup_at_exit_wrapper(void (* f)(),void * arg,void * dso)12013cab2bb3Spatrick static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
12023cab2bb3Spatrick   ENSURE_MSAN_INITED();
12033cab2bb3Spatrick   MSanAtExitRecord *r =
12043cab2bb3Spatrick       (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
12053cab2bb3Spatrick   r->func = (void(*)(void *a))f;
12063cab2bb3Spatrick   r->arg = arg;
12073cab2bb3Spatrick   int res;
12083cab2bb3Spatrick   if (!dso) {
12093cab2bb3Spatrick     // NetBSD does not preserve the 2nd argument if dso is equal to 0
12103cab2bb3Spatrick     // Store ctx in a local stack-like structure
12113cab2bb3Spatrick 
1212*810390e3Srobert     Lock l(&interceptor_ctx()->atexit_mu);
12133cab2bb3Spatrick 
12143cab2bb3Spatrick     res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0);
12153cab2bb3Spatrick     if (!res) {
12163cab2bb3Spatrick       interceptor_ctx()->AtExitStack.PushBack(r);
12173cab2bb3Spatrick     }
12183cab2bb3Spatrick   } else {
12193cab2bb3Spatrick     res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso);
12203cab2bb3Spatrick   }
12213cab2bb3Spatrick   return res;
12223cab2bb3Spatrick }
12233cab2bb3Spatrick 
BeforeFork()12243cab2bb3Spatrick static void BeforeFork() {
12253cab2bb3Spatrick   StackDepotLockAll();
12263cab2bb3Spatrick   ChainedOriginDepotLockAll();
12273cab2bb3Spatrick }
12283cab2bb3Spatrick 
AfterFork()12293cab2bb3Spatrick static void AfterFork() {
12303cab2bb3Spatrick   ChainedOriginDepotUnlockAll();
12313cab2bb3Spatrick   StackDepotUnlockAll();
12323cab2bb3Spatrick }
12333cab2bb3Spatrick 
INTERCEPTOR(int,fork,void)12343cab2bb3Spatrick INTERCEPTOR(int, fork, void) {
12353cab2bb3Spatrick   ENSURE_MSAN_INITED();
12363cab2bb3Spatrick   BeforeFork();
12373cab2bb3Spatrick   int pid = REAL(fork)();
12383cab2bb3Spatrick   AfterFork();
12393cab2bb3Spatrick   return pid;
12403cab2bb3Spatrick }
12413cab2bb3Spatrick 
12423cab2bb3Spatrick // NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly
12433cab2bb3Spatrick // with MSan.
12443cab2bb3Spatrick #if SANITIZER_LINUX
INTERCEPTOR(int,openpty,int * aparent,int * aworker,char * name,const void * termp,const void * winp)12453cab2bb3Spatrick INTERCEPTOR(int, openpty, int *aparent, int *aworker, char *name,
12463cab2bb3Spatrick             const void *termp, const void *winp) {
12473cab2bb3Spatrick   ENSURE_MSAN_INITED();
12483cab2bb3Spatrick   InterceptorScope interceptor_scope;
12493cab2bb3Spatrick   int res = REAL(openpty)(aparent, aworker, name, termp, winp);
12503cab2bb3Spatrick   if (!res) {
12513cab2bb3Spatrick     __msan_unpoison(aparent, sizeof(*aparent));
12523cab2bb3Spatrick     __msan_unpoison(aworker, sizeof(*aworker));
12533cab2bb3Spatrick   }
12543cab2bb3Spatrick   return res;
12553cab2bb3Spatrick }
12563cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_OPENPTY INTERCEPT_FUNCTION(openpty)
12573cab2bb3Spatrick #else
12583cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_OPENPTY
12593cab2bb3Spatrick #endif
12603cab2bb3Spatrick 
12613cab2bb3Spatrick // NetBSD ships with forkpty(3) in -lutil, that needs to be prebuilt explicitly
12623cab2bb3Spatrick // with MSan.
12633cab2bb3Spatrick #if SANITIZER_LINUX
INTERCEPTOR(int,forkpty,int * aparent,char * name,const void * termp,const void * winp)12643cab2bb3Spatrick INTERCEPTOR(int, forkpty, int *aparent, char *name, const void *termp,
12653cab2bb3Spatrick             const void *winp) {
12663cab2bb3Spatrick   ENSURE_MSAN_INITED();
12673cab2bb3Spatrick   InterceptorScope interceptor_scope;
12683cab2bb3Spatrick   int res = REAL(forkpty)(aparent, name, termp, winp);
12693cab2bb3Spatrick   if (res != -1)
12703cab2bb3Spatrick     __msan_unpoison(aparent, sizeof(*aparent));
12713cab2bb3Spatrick   return res;
12723cab2bb3Spatrick }
12733cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FORKPTY INTERCEPT_FUNCTION(forkpty)
12743cab2bb3Spatrick #else
12753cab2bb3Spatrick #define MSAN_MAYBE_INTERCEPT_FORKPTY
12763cab2bb3Spatrick #endif
12773cab2bb3Spatrick 
12783cab2bb3Spatrick struct MSanInterceptorContext {
12793cab2bb3Spatrick   bool in_interceptor_scope;
12803cab2bb3Spatrick };
12813cab2bb3Spatrick 
12823cab2bb3Spatrick namespace __msan {
12833cab2bb3Spatrick 
OnExit()12843cab2bb3Spatrick int OnExit() {
12853cab2bb3Spatrick   // FIXME: ask frontend whether we need to return failure.
12863cab2bb3Spatrick   return 0;
12873cab2bb3Spatrick }
12883cab2bb3Spatrick 
12893cab2bb3Spatrick } // namespace __msan
12903cab2bb3Spatrick 
12913cab2bb3Spatrick // A version of CHECK_UNPOISONED using a saved scope value. Used in common
12923cab2bb3Spatrick // interceptors.
12933cab2bb3Spatrick #define CHECK_UNPOISONED_CTX(ctx, x, n)                         \
12943cab2bb3Spatrick   do {                                                          \
12953cab2bb3Spatrick     if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
12963cab2bb3Spatrick       CHECK_UNPOISONED_0(x, n);                                 \
12973cab2bb3Spatrick   } while (0)
12983cab2bb3Spatrick 
12993cab2bb3Spatrick #define MSAN_INTERCEPT_FUNC(name)                                       \
13003cab2bb3Spatrick   do {                                                                  \
13013cab2bb3Spatrick     if (!INTERCEPT_FUNCTION(name))                                      \
1302d89ec533Spatrick       VReport(1, "MemorySanitizer: failed to intercept '%s'\n", #name); \
13033cab2bb3Spatrick   } while (0)
13043cab2bb3Spatrick 
13053cab2bb3Spatrick #define MSAN_INTERCEPT_FUNC_VER(name, ver)                                 \
13063cab2bb3Spatrick   do {                                                                     \
13073cab2bb3Spatrick     if (!INTERCEPT_FUNCTION_VER(name, ver))                                \
13083cab2bb3Spatrick       VReport(1, "MemorySanitizer: failed to intercept '%s@@%s'\n", #name, \
1309*810390e3Srobert               ver);                                                        \
13103cab2bb3Spatrick   } while (0)
1311d89ec533Spatrick #define MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)             \
1312d89ec533Spatrick   do {                                                                      \
1313d89ec533Spatrick     if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name))    \
1314d89ec533Spatrick       VReport(1, "MemorySanitizer: failed to intercept '%s@@%s' or '%s'\n", \
1315*810390e3Srobert               #name, ver, #name);                                           \
1316d89ec533Spatrick   } while (0)
13173cab2bb3Spatrick 
13183cab2bb3Spatrick #define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
13193cab2bb3Spatrick #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
13203cab2bb3Spatrick   MSAN_INTERCEPT_FUNC_VER(name, ver)
1321d89ec533Spatrick #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
1322d89ec533Spatrick   MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
13233cab2bb3Spatrick #define COMMON_INTERCEPTOR_UNPOISON_PARAM(count)  \
13243cab2bb3Spatrick   UnpoisonParam(count)
13253cab2bb3Spatrick #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
13263cab2bb3Spatrick   __msan_unpoison(ptr, size)
13273cab2bb3Spatrick #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
13283cab2bb3Spatrick   CHECK_UNPOISONED_CTX(ctx, ptr, size)
13293cab2bb3Spatrick #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
13303cab2bb3Spatrick   __msan_unpoison(ptr, size)
13313cab2bb3Spatrick #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)              \
1332*810390e3Srobert   if (msan_init_is_running)                                   \
1333*810390e3Srobert     return REAL(func)(__VA_ARGS__);                           \
13343cab2bb3Spatrick   ENSURE_MSAN_INITED();                                       \
13353cab2bb3Spatrick   MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
13363cab2bb3Spatrick   ctx = (void *)&msan_ctx;                                    \
13373cab2bb3Spatrick   (void)ctx;                                                  \
13383cab2bb3Spatrick   InterceptorScope interceptor_scope;                         \
1339*810390e3Srobert   __msan_unpoison(__errno_location(), sizeof(int));
13403cab2bb3Spatrick #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
13413cab2bb3Spatrick   do {                                            \
13423cab2bb3Spatrick   } while (false)
13433cab2bb3Spatrick #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
13443cab2bb3Spatrick   do {                                         \
13453cab2bb3Spatrick   } while (false)
13463cab2bb3Spatrick #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
13473cab2bb3Spatrick   do {                                         \
13483cab2bb3Spatrick   } while (false)
13493cab2bb3Spatrick #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
13503cab2bb3Spatrick   do {                                                      \
13513cab2bb3Spatrick   } while (false)
13523cab2bb3Spatrick #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
13533cab2bb3Spatrick   do {                                                \
13543cab2bb3Spatrick   } while (false)  // FIXME
13553cab2bb3Spatrick #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
13563cab2bb3Spatrick   do {                                                         \
13573cab2bb3Spatrick   } while (false)  // FIXME
13583cab2bb3Spatrick #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
13593cab2bb3Spatrick #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
13603cab2bb3Spatrick #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)                    \
13613cab2bb3Spatrick   do {                                                                         \
13623cab2bb3Spatrick     link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle));                   \
13633cab2bb3Spatrick     if (filename && map)                                                       \
13643cab2bb3Spatrick       ForEachMappedRegion(map, __msan_unpoison);                               \
13653cab2bb3Spatrick   } while (false)
13663cab2bb3Spatrick 
13671f9cb04fSpatrick #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!msan_inited)
13681f9cb04fSpatrick 
13693cab2bb3Spatrick #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end)                           \
13703cab2bb3Spatrick   if (MsanThread *t = GetCurrentThread()) {                                    \
13713cab2bb3Spatrick     *begin = t->tls_begin();                                                   \
13723cab2bb3Spatrick     *end = t->tls_end();                                                       \
13733cab2bb3Spatrick   } else {                                                                     \
13743cab2bb3Spatrick     *begin = *end = 0;                                                         \
13753cab2bb3Spatrick   }
13763cab2bb3Spatrick 
13773cab2bb3Spatrick #define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
13783cab2bb3Spatrick   {                                                         \
13793cab2bb3Spatrick     (void)ctx;                                              \
13803cab2bb3Spatrick     return __msan_memset(block, c, size);                   \
13813cab2bb3Spatrick   }
13823cab2bb3Spatrick #define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
13833cab2bb3Spatrick   {                                                          \
13843cab2bb3Spatrick     (void)ctx;                                               \
13853cab2bb3Spatrick     return __msan_memmove(to, from, size);                   \
13863cab2bb3Spatrick   }
13873cab2bb3Spatrick #define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
13883cab2bb3Spatrick   {                                                         \
13893cab2bb3Spatrick     (void)ctx;                                              \
13903cab2bb3Spatrick     return __msan_memcpy(to, from, size);                   \
13913cab2bb3Spatrick   }
13923cab2bb3Spatrick 
13933cab2bb3Spatrick #define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \
13943cab2bb3Spatrick   do {                                                      \
13953cab2bb3Spatrick     GET_STORE_STACK_TRACE;                                  \
13963cab2bb3Spatrick     CopyShadowAndOrigin(to, from, size, &stack);            \
13973cab2bb3Spatrick     __msan_unpoison(to + size, 1);                          \
13983cab2bb3Spatrick   } while (false)
13993cab2bb3Spatrick 
14003cab2bb3Spatrick #define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \
14013cab2bb3Spatrick                                      offset)                                   \
14023cab2bb3Spatrick   do {                                                                         \
14033cab2bb3Spatrick     return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);       \
14043cab2bb3Spatrick   } while (false)
14053cab2bb3Spatrick 
14063cab2bb3Spatrick #include "sanitizer_common/sanitizer_platform_interceptors.h"
14073cab2bb3Spatrick #include "sanitizer_common/sanitizer_common_interceptors.inc"
14083cab2bb3Spatrick 
14093cab2bb3Spatrick static uptr signal_impl(int signo, uptr cb);
14103cab2bb3Spatrick static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
14113cab2bb3Spatrick                           __sanitizer_sigaction *oldact);
14123cab2bb3Spatrick 
14133cab2bb3Spatrick #define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \
14143cab2bb3Spatrick   { return sigaction_impl(signo, act, oldact); }
14153cab2bb3Spatrick 
14163cab2bb3Spatrick #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \
14173cab2bb3Spatrick   {                                                          \
14183cab2bb3Spatrick     handler = signal_impl(signo, handler);                   \
14193cab2bb3Spatrick     InterceptorScope interceptor_scope;                      \
14203cab2bb3Spatrick     return REAL(func)(signo, handler);                       \
14213cab2bb3Spatrick   }
14223cab2bb3Spatrick 
14233cab2bb3Spatrick #include "sanitizer_common/sanitizer_signal_interceptors.inc"
14243cab2bb3Spatrick 
sigaction_impl(int signo,const __sanitizer_sigaction * act,__sanitizer_sigaction * oldact)14253cab2bb3Spatrick static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
14263cab2bb3Spatrick                           __sanitizer_sigaction *oldact) {
14273cab2bb3Spatrick   ENSURE_MSAN_INITED();
1428d89ec533Spatrick   if (signo <= 0 || signo >= kMaxSignals) {
1429d89ec533Spatrick     errno = errno_EINVAL;
1430d89ec533Spatrick     return -1;
1431d89ec533Spatrick   }
14323cab2bb3Spatrick   if (act) read_sigaction(act);
14333cab2bb3Spatrick   int res;
14343cab2bb3Spatrick   if (flags()->wrap_signals) {
14353cab2bb3Spatrick     SpinMutexLock lock(&sigactions_mu);
14363cab2bb3Spatrick     uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
14373cab2bb3Spatrick     __sanitizer_sigaction new_act;
14383cab2bb3Spatrick     __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
14393cab2bb3Spatrick     if (act) {
14403cab2bb3Spatrick       REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
14413cab2bb3Spatrick       uptr cb = (uptr)pnew_act->sigaction;
14423cab2bb3Spatrick       uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
14433cab2bb3Spatrick                         ? (uptr)SignalAction
14443cab2bb3Spatrick                         : (uptr)SignalHandler;
14453cab2bb3Spatrick       if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
14463cab2bb3Spatrick         atomic_store(&sigactions[signo], cb, memory_order_relaxed);
14473cab2bb3Spatrick         pnew_act->sigaction = (decltype(pnew_act->sigaction))new_cb;
14483cab2bb3Spatrick       }
14493cab2bb3Spatrick     }
14503cab2bb3Spatrick     res = REAL(SIGACTION_SYMNAME)(signo, pnew_act, oldact);
14513cab2bb3Spatrick     if (res == 0 && oldact) {
14523cab2bb3Spatrick       uptr cb = (uptr)oldact->sigaction;
14533cab2bb3Spatrick       if (cb == (uptr)SignalAction || cb == (uptr)SignalHandler) {
14543cab2bb3Spatrick         oldact->sigaction = (decltype(oldact->sigaction))old_cb;
14553cab2bb3Spatrick       }
14563cab2bb3Spatrick     }
14573cab2bb3Spatrick   } else {
14583cab2bb3Spatrick     res = REAL(SIGACTION_SYMNAME)(signo, act, oldact);
14593cab2bb3Spatrick   }
14603cab2bb3Spatrick 
14613cab2bb3Spatrick   if (res == 0 && oldact) {
14623cab2bb3Spatrick     __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
14633cab2bb3Spatrick   }
14643cab2bb3Spatrick   return res;
14653cab2bb3Spatrick }
14663cab2bb3Spatrick 
signal_impl(int signo,uptr cb)14673cab2bb3Spatrick static uptr signal_impl(int signo, uptr cb) {
14683cab2bb3Spatrick   ENSURE_MSAN_INITED();
1469d89ec533Spatrick   if (signo <= 0 || signo >= kMaxSignals) {
1470d89ec533Spatrick     errno = errno_EINVAL;
1471d89ec533Spatrick     return -1;
1472d89ec533Spatrick   }
14733cab2bb3Spatrick   if (flags()->wrap_signals) {
14743cab2bb3Spatrick     SpinMutexLock lock(&sigactions_mu);
14753cab2bb3Spatrick     if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
14763cab2bb3Spatrick       atomic_store(&sigactions[signo], cb, memory_order_relaxed);
14773cab2bb3Spatrick       cb = (uptr)&SignalHandler;
14783cab2bb3Spatrick     }
14793cab2bb3Spatrick   }
14803cab2bb3Spatrick   return cb;
14813cab2bb3Spatrick }
14823cab2bb3Spatrick 
14833cab2bb3Spatrick #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
14843cab2bb3Spatrick #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
14853cab2bb3Spatrick   do {                                       \
14863cab2bb3Spatrick   } while (false)
14873cab2bb3Spatrick #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
14883cab2bb3Spatrick   do {                                       \
14893cab2bb3Spatrick   } while (false)
14903cab2bb3Spatrick #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
14913cab2bb3Spatrick #include "sanitizer_common/sanitizer_common_syscalls.inc"
14923cab2bb3Spatrick #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
14933cab2bb3Spatrick 
INTERCEPTOR(const char *,strsignal,int sig)1494*810390e3Srobert INTERCEPTOR(const char *, strsignal, int sig) {
1495*810390e3Srobert   void *ctx;
1496*810390e3Srobert   COMMON_INTERCEPTOR_ENTER(ctx, strsignal, sig);
1497*810390e3Srobert   const char *res = REAL(strsignal)(sig);
1498*810390e3Srobert   if (res)
1499*810390e3Srobert     __msan_unpoison(res, internal_strlen(res) + 1);
1500*810390e3Srobert   return res;
1501*810390e3Srobert }
1502*810390e3Srobert 
15033cab2bb3Spatrick struct dlinfo {
15043cab2bb3Spatrick   char *dli_fname;
15053cab2bb3Spatrick   void *dli_fbase;
15063cab2bb3Spatrick   char *dli_sname;
15073cab2bb3Spatrick   void *dli_saddr;
15083cab2bb3Spatrick };
15093cab2bb3Spatrick 
INTERCEPTOR(int,dladdr,void * addr,dlinfo * info)15103cab2bb3Spatrick INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
15113cab2bb3Spatrick   void *ctx;
15123cab2bb3Spatrick   COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info);
15133cab2bb3Spatrick   int res = REAL(dladdr)(addr, info);
15143cab2bb3Spatrick   if (res != 0) {
15153cab2bb3Spatrick     __msan_unpoison(info, sizeof(*info));
15163cab2bb3Spatrick     if (info->dli_fname)
1517*810390e3Srobert       __msan_unpoison(info->dli_fname, internal_strlen(info->dli_fname) + 1);
15183cab2bb3Spatrick     if (info->dli_sname)
1519*810390e3Srobert       __msan_unpoison(info->dli_sname, internal_strlen(info->dli_sname) + 1);
15203cab2bb3Spatrick   }
15213cab2bb3Spatrick   return res;
15223cab2bb3Spatrick }
15233cab2bb3Spatrick 
INTERCEPTOR(char *,dlerror,int fake)15243cab2bb3Spatrick INTERCEPTOR(char *, dlerror, int fake) {
15253cab2bb3Spatrick   void *ctx;
15263cab2bb3Spatrick   COMMON_INTERCEPTOR_ENTER(ctx, dlerror, fake);
15273cab2bb3Spatrick   char *res = REAL(dlerror)(fake);
1528*810390e3Srobert   if (res)
1529*810390e3Srobert     __msan_unpoison(res, internal_strlen(res) + 1);
15303cab2bb3Spatrick   return res;
15313cab2bb3Spatrick }
15323cab2bb3Spatrick 
15333cab2bb3Spatrick typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
15343cab2bb3Spatrick                                   void *data);
15353cab2bb3Spatrick struct dl_iterate_phdr_data {
15363cab2bb3Spatrick   dl_iterate_phdr_cb callback;
15373cab2bb3Spatrick   void *data;
15383cab2bb3Spatrick };
15393cab2bb3Spatrick 
msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info * info,SIZE_T size,void * data)15403cab2bb3Spatrick static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
15413cab2bb3Spatrick                                    void *data) {
15423cab2bb3Spatrick   if (info) {
15433cab2bb3Spatrick     __msan_unpoison(info, size);
15443cab2bb3Spatrick     if (info->dlpi_phdr && info->dlpi_phnum)
15453cab2bb3Spatrick       __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum);
15463cab2bb3Spatrick     if (info->dlpi_name)
1547*810390e3Srobert       __msan_unpoison(info->dlpi_name, internal_strlen(info->dlpi_name) + 1);
15483cab2bb3Spatrick   }
15493cab2bb3Spatrick   dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
15503cab2bb3Spatrick   UnpoisonParam(3);
15513cab2bb3Spatrick   return cbdata->callback(info, size, cbdata->data);
15523cab2bb3Spatrick }
15533cab2bb3Spatrick 
INTERCEPTOR(void *,shmat,int shmid,const void * shmaddr,int shmflg)15543cab2bb3Spatrick INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
15553cab2bb3Spatrick   ENSURE_MSAN_INITED();
15563cab2bb3Spatrick   void *p = REAL(shmat)(shmid, shmaddr, shmflg);
15573cab2bb3Spatrick   if (p != (void *)-1) {
15583cab2bb3Spatrick     __sanitizer_shmid_ds ds;
15593cab2bb3Spatrick     int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
15603cab2bb3Spatrick     if (!res) {
15613cab2bb3Spatrick       __msan_unpoison(p, ds.shm_segsz);
15623cab2bb3Spatrick     }
15633cab2bb3Spatrick   }
15643cab2bb3Spatrick   return p;
15653cab2bb3Spatrick }
15663cab2bb3Spatrick 
INTERCEPTOR(int,dl_iterate_phdr,dl_iterate_phdr_cb callback,void * data)15673cab2bb3Spatrick INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
15683cab2bb3Spatrick   void *ctx;
15693cab2bb3Spatrick   COMMON_INTERCEPTOR_ENTER(ctx, dl_iterate_phdr, callback, data);
15703cab2bb3Spatrick   dl_iterate_phdr_data cbdata;
15713cab2bb3Spatrick   cbdata.callback = callback;
15723cab2bb3Spatrick   cbdata.data = data;
15733cab2bb3Spatrick   int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
15743cab2bb3Spatrick   return res;
15753cab2bb3Spatrick }
15763cab2bb3Spatrick 
15773cab2bb3Spatrick // wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
INTERCEPTOR(wchar_t *,wcschr,void * s,wchar_t wc,void * ps)15783cab2bb3Spatrick INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
15793cab2bb3Spatrick   ENSURE_MSAN_INITED();
15803cab2bb3Spatrick   wchar_t *res = REAL(wcschr)(s, wc, ps);
15813cab2bb3Spatrick   return res;
15823cab2bb3Spatrick }
15833cab2bb3Spatrick 
15843cab2bb3Spatrick // wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
INTERCEPTOR(wchar_t *,wcscpy,wchar_t * dest,const wchar_t * src)15853cab2bb3Spatrick INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
15863cab2bb3Spatrick   ENSURE_MSAN_INITED();
15873cab2bb3Spatrick   GET_STORE_STACK_TRACE;
15883cab2bb3Spatrick   wchar_t *res = REAL(wcscpy)(dest, src);
1589*810390e3Srobert   CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (internal_wcslen(src) + 1),
15903cab2bb3Spatrick                       &stack);
15913cab2bb3Spatrick   return res;
15923cab2bb3Spatrick }
15933cab2bb3Spatrick 
INTERCEPTOR(wchar_t *,wcsncpy,wchar_t * dest,const wchar_t * src,SIZE_T n)15943cab2bb3Spatrick INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
15953cab2bb3Spatrick   ENSURE_MSAN_INITED();
15963cab2bb3Spatrick   GET_STORE_STACK_TRACE;
1597*810390e3Srobert   SIZE_T copy_size = internal_wcsnlen(src, n);
15983cab2bb3Spatrick   if (copy_size < n) copy_size++;           // trailing \0
15993cab2bb3Spatrick   wchar_t *res = REAL(wcsncpy)(dest, src, n);
16003cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack);
16013cab2bb3Spatrick   __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t));
16023cab2bb3Spatrick   return res;
16033cab2bb3Spatrick }
16043cab2bb3Spatrick 
16053cab2bb3Spatrick // These interface functions reside here so that they can use
16063cab2bb3Spatrick // REAL(memset), etc.
__msan_unpoison(const void * a,uptr size)16073cab2bb3Spatrick void __msan_unpoison(const void *a, uptr size) {
16083cab2bb3Spatrick   if (!MEM_IS_APP(a)) return;
16093cab2bb3Spatrick   SetShadow(a, size, 0);
16103cab2bb3Spatrick }
16113cab2bb3Spatrick 
__msan_poison(const void * a,uptr size)16123cab2bb3Spatrick void __msan_poison(const void *a, uptr size) {
16133cab2bb3Spatrick   if (!MEM_IS_APP(a)) return;
16143cab2bb3Spatrick   SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
16153cab2bb3Spatrick }
16163cab2bb3Spatrick 
__msan_poison_stack(void * a,uptr size)16173cab2bb3Spatrick void __msan_poison_stack(void *a, uptr size) {
16183cab2bb3Spatrick   if (!MEM_IS_APP(a)) return;
16193cab2bb3Spatrick   SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
16203cab2bb3Spatrick }
16213cab2bb3Spatrick 
__msan_unpoison_param(uptr n)16223cab2bb3Spatrick void __msan_unpoison_param(uptr n) { UnpoisonParam(n); }
16233cab2bb3Spatrick 
__msan_clear_and_unpoison(void * a,uptr size)16243cab2bb3Spatrick void __msan_clear_and_unpoison(void *a, uptr size) {
16253cab2bb3Spatrick   REAL(memset)(a, 0, size);
16263cab2bb3Spatrick   SetShadow(a, size, 0);
16273cab2bb3Spatrick }
16283cab2bb3Spatrick 
__msan_memcpy(void * dest,const void * src,SIZE_T n)16293cab2bb3Spatrick void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
16303cab2bb3Spatrick   if (!msan_inited) return internal_memcpy(dest, src, n);
1631*810390e3Srobert   if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
16323cab2bb3Spatrick     return REAL(memcpy)(dest, src, n);
16333cab2bb3Spatrick   ENSURE_MSAN_INITED();
16343cab2bb3Spatrick   GET_STORE_STACK_TRACE;
16353cab2bb3Spatrick   void *res = REAL(memcpy)(dest, src, n);
16363cab2bb3Spatrick   CopyShadowAndOrigin(dest, src, n, &stack);
16373cab2bb3Spatrick   return res;
16383cab2bb3Spatrick }
16393cab2bb3Spatrick 
__msan_memset(void * s,int c,SIZE_T n)16403cab2bb3Spatrick void *__msan_memset(void *s, int c, SIZE_T n) {
16413cab2bb3Spatrick   if (!msan_inited) return internal_memset(s, c, n);
16423cab2bb3Spatrick   if (msan_init_is_running) return REAL(memset)(s, c, n);
16433cab2bb3Spatrick   ENSURE_MSAN_INITED();
16443cab2bb3Spatrick   void *res = REAL(memset)(s, c, n);
16453cab2bb3Spatrick   __msan_unpoison(s, n);
16463cab2bb3Spatrick   return res;
16473cab2bb3Spatrick }
16483cab2bb3Spatrick 
__msan_memmove(void * dest,const void * src,SIZE_T n)16493cab2bb3Spatrick void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
16503cab2bb3Spatrick   if (!msan_inited) return internal_memmove(dest, src, n);
16513cab2bb3Spatrick   if (msan_init_is_running) return REAL(memmove)(dest, src, n);
16523cab2bb3Spatrick   ENSURE_MSAN_INITED();
16533cab2bb3Spatrick   GET_STORE_STACK_TRACE;
16543cab2bb3Spatrick   void *res = REAL(memmove)(dest, src, n);
16553cab2bb3Spatrick   MoveShadowAndOrigin(dest, src, n, &stack);
16563cab2bb3Spatrick   return res;
16573cab2bb3Spatrick }
16583cab2bb3Spatrick 
__msan_unpoison_string(const char * s)16593cab2bb3Spatrick void __msan_unpoison_string(const char* s) {
16603cab2bb3Spatrick   if (!MEM_IS_APP(s)) return;
1661*810390e3Srobert   __msan_unpoison(s, internal_strlen(s) + 1);
16623cab2bb3Spatrick }
16633cab2bb3Spatrick 
16643cab2bb3Spatrick namespace __msan {
16653cab2bb3Spatrick 
InitializeInterceptors()16663cab2bb3Spatrick void InitializeInterceptors() {
16673cab2bb3Spatrick   static int inited = 0;
16683cab2bb3Spatrick   CHECK_EQ(inited, 0);
16693cab2bb3Spatrick 
16703cab2bb3Spatrick   new(interceptor_ctx()) InterceptorContext();
16713cab2bb3Spatrick 
16723cab2bb3Spatrick   InitializeCommonInterceptors();
16733cab2bb3Spatrick   InitializeSignalInterceptors();
16743cab2bb3Spatrick 
16753cab2bb3Spatrick   INTERCEPT_FUNCTION(posix_memalign);
16763cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MEMALIGN;
16773cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
16783cab2bb3Spatrick   INTERCEPT_FUNCTION(valloc);
16793cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_PVALLOC;
16803cab2bb3Spatrick   INTERCEPT_FUNCTION(malloc);
16813cab2bb3Spatrick   INTERCEPT_FUNCTION(calloc);
16823cab2bb3Spatrick   INTERCEPT_FUNCTION(realloc);
16833cab2bb3Spatrick   INTERCEPT_FUNCTION(reallocarray);
16843cab2bb3Spatrick   INTERCEPT_FUNCTION(free);
16853cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_CFREE;
16863cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
16873cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MALLINFO;
16883cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MALLOPT;
16893cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
16903cab2bb3Spatrick   INTERCEPT_FUNCTION(fread);
16913cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
16923cab2bb3Spatrick   INTERCEPT_FUNCTION(memccpy);
16933cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_MEMPCPY;
16943cab2bb3Spatrick   INTERCEPT_FUNCTION(bcopy);
16953cab2bb3Spatrick   INTERCEPT_FUNCTION(wmemset);
16963cab2bb3Spatrick   INTERCEPT_FUNCTION(wmemcpy);
16973cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_WMEMPCPY;
16983cab2bb3Spatrick   INTERCEPT_FUNCTION(wmemmove);
16993cab2bb3Spatrick   INTERCEPT_FUNCTION(strcpy);
17003cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_STPCPY;
1701*810390e3Srobert   MSAN_MAYBE_INTERCEPT_STPNCPY;
17023cab2bb3Spatrick   INTERCEPT_FUNCTION(strdup);
17033cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___STRDUP;
17043cab2bb3Spatrick   INTERCEPT_FUNCTION(strncpy);
17053cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_GCVT;
17063cab2bb3Spatrick   INTERCEPT_FUNCTION(strcat);
17073cab2bb3Spatrick   INTERCEPT_FUNCTION(strncat);
17083cab2bb3Spatrick   INTERCEPT_STRTO(strtod);
17093cab2bb3Spatrick   INTERCEPT_STRTO(strtof);
17103cab2bb3Spatrick   INTERCEPT_STRTO(strtold);
17113cab2bb3Spatrick   INTERCEPT_STRTO(strtol);
17123cab2bb3Spatrick   INTERCEPT_STRTO(strtoul);
17133cab2bb3Spatrick   INTERCEPT_STRTO(strtoll);
17143cab2bb3Spatrick   INTERCEPT_STRTO(strtoull);
17153cab2bb3Spatrick   INTERCEPT_STRTO(strtouq);
17163cab2bb3Spatrick   INTERCEPT_STRTO(wcstod);
17173cab2bb3Spatrick   INTERCEPT_STRTO(wcstof);
17183cab2bb3Spatrick   INTERCEPT_STRTO(wcstold);
17193cab2bb3Spatrick   INTERCEPT_STRTO(wcstol);
17203cab2bb3Spatrick   INTERCEPT_STRTO(wcstoul);
17213cab2bb3Spatrick   INTERCEPT_STRTO(wcstoll);
17223cab2bb3Spatrick   INTERCEPT_STRTO(wcstoull);
17233cab2bb3Spatrick #ifdef SANITIZER_NLDBL_VERSION
17243cab2bb3Spatrick   INTERCEPT_FUNCTION_VER(vswprintf, SANITIZER_NLDBL_VERSION);
17253cab2bb3Spatrick   INTERCEPT_FUNCTION_VER(swprintf, SANITIZER_NLDBL_VERSION);
17263cab2bb3Spatrick #else
17273cab2bb3Spatrick   INTERCEPT_FUNCTION(vswprintf);
17283cab2bb3Spatrick   INTERCEPT_FUNCTION(swprintf);
17293cab2bb3Spatrick #endif
17303cab2bb3Spatrick   INTERCEPT_FUNCTION(strftime);
17313cab2bb3Spatrick   INTERCEPT_FUNCTION(strftime_l);
17323cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___STRFTIME_L;
17333cab2bb3Spatrick   INTERCEPT_FUNCTION(wcsftime);
17343cab2bb3Spatrick   INTERCEPT_FUNCTION(wcsftime_l);
17353cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
17363cab2bb3Spatrick   INTERCEPT_FUNCTION(mbtowc);
17373cab2bb3Spatrick   INTERCEPT_FUNCTION(mbrtowc);
17383cab2bb3Spatrick   INTERCEPT_FUNCTION(wcslen);
17393cab2bb3Spatrick   INTERCEPT_FUNCTION(wcsnlen);
17403cab2bb3Spatrick   INTERCEPT_FUNCTION(wcschr);
17413cab2bb3Spatrick   INTERCEPT_FUNCTION(wcscpy);
17423cab2bb3Spatrick   INTERCEPT_FUNCTION(wcsncpy);
17433cab2bb3Spatrick   INTERCEPT_FUNCTION(wcscmp);
17443cab2bb3Spatrick   INTERCEPT_FUNCTION(getenv);
17453cab2bb3Spatrick   INTERCEPT_FUNCTION(setenv);
17463cab2bb3Spatrick   INTERCEPT_FUNCTION(putenv);
17473cab2bb3Spatrick   INTERCEPT_FUNCTION(gettimeofday);
17483cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_FCVT;
17493cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_FSTAT;
1750*810390e3Srobert   MSAN_MAYBE_INTERCEPT_FSTAT64;
17513cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___FXSTAT;
1752*810390e3Srobert   MSAN_MAYBE_INTERCEPT_FSTATAT;
1753*810390e3Srobert   MSAN_MAYBE_INTERCEPT_FSTATAT64;
1754*810390e3Srobert   MSAN_MAYBE_INTERCEPT___FXSTATAT;
17553cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___FXSTAT64;
17563cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___FXSTATAT64;
17573cab2bb3Spatrick   INTERCEPT_FUNCTION(pipe);
17583cab2bb3Spatrick   INTERCEPT_FUNCTION(pipe2);
17593cab2bb3Spatrick   INTERCEPT_FUNCTION(socketpair);
17603cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
17613cab2bb3Spatrick   INTERCEPT_FUNCTION(getrlimit);
17623cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT___GETRLIMIT;
17633cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
17643cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_PRLIMIT;
17653cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_PRLIMIT64;
17663cab2bb3Spatrick   INTERCEPT_FUNCTION(gethostname);
17673cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
17683cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
1769*810390e3Srobert   INTERCEPT_FUNCTION(strsignal);
17703cab2bb3Spatrick   INTERCEPT_FUNCTION(dladdr);
17713cab2bb3Spatrick   INTERCEPT_FUNCTION(dlerror);
17723cab2bb3Spatrick   INTERCEPT_FUNCTION(dl_iterate_phdr);
17733cab2bb3Spatrick   INTERCEPT_FUNCTION(getrusage);
17743cab2bb3Spatrick #if defined(__mips__)
17753cab2bb3Spatrick   INTERCEPT_FUNCTION_VER(pthread_create, "GLIBC_2.2");
17763cab2bb3Spatrick #else
17773cab2bb3Spatrick   INTERCEPT_FUNCTION(pthread_create);
17783cab2bb3Spatrick #endif
1779*810390e3Srobert   INTERCEPT_FUNCTION(pthread_join);
17803cab2bb3Spatrick   INTERCEPT_FUNCTION(pthread_key_create);
17813cab2bb3Spatrick 
17823cab2bb3Spatrick #if SANITIZER_NETBSD
17833cab2bb3Spatrick   INTERCEPT_FUNCTION(__libc_thr_keycreate);
17843cab2bb3Spatrick #endif
17853cab2bb3Spatrick 
17863cab2bb3Spatrick   INTERCEPT_FUNCTION(pthread_join);
17873cab2bb3Spatrick   INTERCEPT_FUNCTION(tzset);
17883cab2bb3Spatrick   INTERCEPT_FUNCTION(atexit);
17893cab2bb3Spatrick   INTERCEPT_FUNCTION(__cxa_atexit);
17903cab2bb3Spatrick   INTERCEPT_FUNCTION(shmat);
17913cab2bb3Spatrick   INTERCEPT_FUNCTION(fork);
17923cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_OPENPTY;
17933cab2bb3Spatrick   MSAN_MAYBE_INTERCEPT_FORKPTY;
17943cab2bb3Spatrick 
17953cab2bb3Spatrick   inited = 1;
17963cab2bb3Spatrick }
17973cab2bb3Spatrick } // namespace __msan
1798