1353944Sdim//===-- msan_interceptors.cpp ---------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of MemorySanitizer.
10353944Sdim//
11353944Sdim// Interceptors for standard library functions.
12353944Sdim//
13353944Sdim// FIXME: move as many interceptors as possible into
14353944Sdim// sanitizer_common/sanitizer_common_interceptors.h
15353944Sdim//===----------------------------------------------------------------------===//
16353944Sdim
17353944Sdim#include "interception/interception.h"
18353944Sdim#include "msan.h"
19353944Sdim#include "msan_chained_origin_depot.h"
20353944Sdim#include "msan_origin.h"
21353944Sdim#include "msan_report.h"
22353944Sdim#include "msan_thread.h"
23353944Sdim#include "msan_poisoning.h"
24353944Sdim#include "sanitizer_common/sanitizer_platform_limits_posix.h"
25353944Sdim#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
26353944Sdim#include "sanitizer_common/sanitizer_allocator.h"
27353944Sdim#include "sanitizer_common/sanitizer_allocator_interface.h"
28353944Sdim#include "sanitizer_common/sanitizer_allocator_internal.h"
29353944Sdim#include "sanitizer_common/sanitizer_atomic.h"
30353944Sdim#include "sanitizer_common/sanitizer_common.h"
31353944Sdim#include "sanitizer_common/sanitizer_errno.h"
32353944Sdim#include "sanitizer_common/sanitizer_stackdepot.h"
33353944Sdim#include "sanitizer_common/sanitizer_libc.h"
34353944Sdim#include "sanitizer_common/sanitizer_linux.h"
35353944Sdim#include "sanitizer_common/sanitizer_tls_get_addr.h"
36353944Sdim#include "sanitizer_common/sanitizer_vector.h"
37353944Sdim
38353944Sdim#if SANITIZER_NETBSD
39353944Sdim#define fstat __fstat50
40353944Sdim#define gettimeofday __gettimeofday50
41353944Sdim#define getrusage __getrusage50
42353944Sdim#define tzset __tzset50
43353944Sdim#endif
44353944Sdim
45353944Sdim#include <stdarg.h>
46353944Sdim// ACHTUNG! No other system header includes in this file.
47353944Sdim// Ideally, we should get rid of stdarg.h as well.
48353944Sdim
49353944Sdimusing namespace __msan;
50353944Sdim
51353944Sdimusing __sanitizer::memory_order;
52353944Sdimusing __sanitizer::atomic_load;
53353944Sdimusing __sanitizer::atomic_store;
54353944Sdimusing __sanitizer::atomic_uintptr_t;
55353944Sdim
56353944SdimDECLARE_REAL(SIZE_T, strlen, const char *s)
57353944SdimDECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
58353944SdimDECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
59353944SdimDECLARE_REAL(void *, memset, void *dest, int c, uptr n)
60353944Sdim
61353944Sdim// True if this is a nested interceptor.
62353944Sdimstatic THREADLOCAL int in_interceptor_scope;
63353944Sdim
64353944Sdimvoid __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; }
65353944Sdimvoid __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; }
66353944Sdim
67353944Sdimstruct InterceptorScope {
68353944Sdim  InterceptorScope() { ++in_interceptor_scope; }
69353944Sdim  ~InterceptorScope() { --in_interceptor_scope; }
70353944Sdim};
71353944Sdim
72353944Sdimbool IsInInterceptorScope() {
73353944Sdim  return in_interceptor_scope;
74353944Sdim}
75353944Sdim
76353944Sdimstatic uptr allocated_for_dlsym;
77353944Sdimstatic const uptr kDlsymAllocPoolSize = 1024;
78353944Sdimstatic uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
79353944Sdim
80353944Sdimstatic bool IsInDlsymAllocPool(const void *ptr) {
81353944Sdim  uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
82353944Sdim  return off < sizeof(alloc_memory_for_dlsym);
83353944Sdim}
84353944Sdim
85353944Sdimstatic void *AllocateFromLocalPool(uptr size_in_bytes) {
86353944Sdim  uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
87353944Sdim  void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym];
88353944Sdim  allocated_for_dlsym += size_in_words;
89353944Sdim  CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
90353944Sdim  return mem;
91353944Sdim}
92353944Sdim
93353944Sdim#define ENSURE_MSAN_INITED() do { \
94353944Sdim  CHECK(!msan_init_is_running); \
95353944Sdim  if (!msan_inited) { \
96353944Sdim    __msan_init(); \
97353944Sdim  } \
98353944Sdim} while (0)
99353944Sdim
100353944Sdim// Check that [x, x+n) range is unpoisoned.
101353944Sdim#define CHECK_UNPOISONED_0(x, n)                                  \
102353944Sdim  do {                                                            \
103353944Sdim    sptr __offset = __msan_test_shadow(x, n);                     \
104353944Sdim    if (__msan::IsInSymbolizer()) break;                          \
105353944Sdim    if (__offset >= 0 && __msan::flags()->report_umrs) {          \
106353944Sdim      GET_CALLER_PC_BP_SP;                                        \
107353944Sdim      (void)sp;                                                   \
108353944Sdim      ReportUMRInsideAddressRange(__func__, x, n, __offset);      \
109353944Sdim      __msan::PrintWarningWithOrigin(                             \
110353944Sdim          pc, bp, __msan_get_origin((const char *)x + __offset)); \
111353944Sdim      if (__msan::flags()->halt_on_error) {                       \
112353944Sdim        Printf("Exiting\n");                                      \
113353944Sdim        Die();                                                    \
114353944Sdim      }                                                           \
115353944Sdim    }                                                             \
116353944Sdim  } while (0)
117353944Sdim
118353944Sdim// Check that [x, x+n) range is unpoisoned unless we are in a nested
119353944Sdim// interceptor.
120353944Sdim#define CHECK_UNPOISONED(x, n)                             \
121353944Sdim  do {                                                     \
122353944Sdim    if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
123353944Sdim  } while (0)
124353944Sdim
125353944Sdim#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n)               \
126353944Sdim  CHECK_UNPOISONED((x),                                         \
127353944Sdim    common_flags()->strict_string_checks ? (len) + 1 : (n) )
128353944Sdim
129353944Sdim#define CHECK_UNPOISONED_STRING(x, n)                           \
130353944Sdim    CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
131353944Sdim
132353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
133353944SdimINTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
134353944Sdim            void *file) {
135353944Sdim  ENSURE_MSAN_INITED();
136353944Sdim  SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file);
137353944Sdim  if (res > 0)
138353944Sdim    __msan_unpoison(ptr, res *size);
139353944Sdim  return res;
140353944Sdim}
141353944Sdim#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
142353944Sdim#else
143353944Sdim#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
144353944Sdim#endif
145353944Sdim
146353944Sdim#if !SANITIZER_NETBSD
147353944SdimINTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
148353944Sdim  return (char *)__msan_memcpy(dest, src, n) + n;
149353944Sdim}
150353944Sdim#define MSAN_MAYBE_INTERCEPT_MEMPCPY INTERCEPT_FUNCTION(mempcpy)
151353944Sdim#else
152353944Sdim#define MSAN_MAYBE_INTERCEPT_MEMPCPY
153353944Sdim#endif
154353944Sdim
155353944SdimINTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
156353944Sdim  ENSURE_MSAN_INITED();
157353944Sdim  void *res = REAL(memccpy)(dest, src, c, n);
158353944Sdim  CHECK(!res || (res >= dest && res <= (char *)dest + n));
159353944Sdim  SIZE_T sz = res ? (char *)res - (char *)dest : n;
160353944Sdim  CHECK_UNPOISONED(src, sz);
161353944Sdim  __msan_unpoison(dest, sz);
162353944Sdim  return res;
163353944Sdim}
164353944Sdim
165353944SdimINTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
166353944Sdim  return __msan_memmove(dest, src, n);
167353944Sdim}
168353944Sdim
169353944SdimINTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
170353944Sdim  GET_MALLOC_STACK_TRACE;
171353944Sdim  CHECK_NE(memptr, 0);
172353944Sdim  int res = msan_posix_memalign(memptr, alignment, size, &stack);
173353944Sdim  if (!res)
174353944Sdim    __msan_unpoison(memptr, sizeof(*memptr));
175353944Sdim  return res;
176353944Sdim}
177353944Sdim
178353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
179353944SdimINTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
180353944Sdim  GET_MALLOC_STACK_TRACE;
181353944Sdim  return msan_memalign(alignment, size, &stack);
182353944Sdim}
183353944Sdim#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
184353944Sdim#else
185353944Sdim#define MSAN_MAYBE_INTERCEPT_MEMALIGN
186353944Sdim#endif
187353944Sdim
188353944SdimINTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
189353944Sdim  GET_MALLOC_STACK_TRACE;
190353944Sdim  return msan_aligned_alloc(alignment, size, &stack);
191353944Sdim}
192353944Sdim
193353944Sdim#if !SANITIZER_NETBSD
194353944SdimINTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
195353944Sdim  GET_MALLOC_STACK_TRACE;
196353944Sdim  void *ptr = msan_memalign(alignment, size, &stack);
197353944Sdim  if (ptr)
198353944Sdim    DTLS_on_libc_memalign(ptr, size);
199353944Sdim  return ptr;
200353944Sdim}
201353944Sdim#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
202353944Sdim#else
203353944Sdim#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
204353944Sdim#endif
205353944Sdim
206353944SdimINTERCEPTOR(void *, valloc, SIZE_T size) {
207353944Sdim  GET_MALLOC_STACK_TRACE;
208353944Sdim  return msan_valloc(size, &stack);
209353944Sdim}
210353944Sdim
211353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
212353944SdimINTERCEPTOR(void *, pvalloc, SIZE_T size) {
213353944Sdim  GET_MALLOC_STACK_TRACE;
214353944Sdim  return msan_pvalloc(size, &stack);
215353944Sdim}
216353944Sdim#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
217353944Sdim#else
218353944Sdim#define MSAN_MAYBE_INTERCEPT_PVALLOC
219353944Sdim#endif
220353944Sdim
221353944SdimINTERCEPTOR(void, free, void *ptr) {
222353944Sdim  GET_MALLOC_STACK_TRACE;
223353944Sdim  if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
224353944Sdim  MsanDeallocate(&stack, ptr);
225353944Sdim}
226353944Sdim
227353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
228353944SdimINTERCEPTOR(void, cfree, void *ptr) {
229353944Sdim  GET_MALLOC_STACK_TRACE;
230353944Sdim  if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
231353944Sdim  MsanDeallocate(&stack, ptr);
232353944Sdim}
233353944Sdim#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
234353944Sdim#else
235353944Sdim#define MSAN_MAYBE_INTERCEPT_CFREE
236353944Sdim#endif
237353944Sdim
238353944Sdim#if !SANITIZER_NETBSD
239353944SdimINTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
240353944Sdim  return __sanitizer_get_allocated_size(ptr);
241353944Sdim}
242353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
243353944Sdim  INTERCEPT_FUNCTION(malloc_usable_size)
244353944Sdim#else
245353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
246353944Sdim#endif
247353944Sdim
248353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
249353944Sdim// This function actually returns a struct by value, but we can't unpoison a
250353944Sdim// temporary! The following is equivalent on all supported platforms but
251353944Sdim// aarch64 (which uses a different register for sret value).  We have a test
252353944Sdim// to confirm that.
253353944SdimINTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) {
254353944Sdim#ifdef __aarch64__
255353944Sdim  uptr r8;
256353944Sdim  asm volatile("mov %0,x8" : "=r" (r8));
257353944Sdim  sret = reinterpret_cast<__sanitizer_struct_mallinfo*>(r8);
258353944Sdim#endif
259353944Sdim  REAL(memset)(sret, 0, sizeof(*sret));
260353944Sdim  __msan_unpoison(sret, sizeof(*sret));
261353944Sdim}
262353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
263353944Sdim#else
264353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLINFO
265353944Sdim#endif
266353944Sdim
267353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
268353944SdimINTERCEPTOR(int, mallopt, int cmd, int value) {
269353944Sdim  return 0;
270353944Sdim}
271353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
272353944Sdim#else
273353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOPT
274353944Sdim#endif
275353944Sdim
276353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
277353944SdimINTERCEPTOR(void, malloc_stats, void) {
278353944Sdim  // FIXME: implement, but don't call REAL(malloc_stats)!
279353944Sdim}
280353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
281353944Sdim#else
282353944Sdim#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
283353944Sdim#endif
284353944Sdim
285353944SdimINTERCEPTOR(char *, strcpy, char *dest, const char *src) {
286353944Sdim  ENSURE_MSAN_INITED();
287353944Sdim  GET_STORE_STACK_TRACE;
288353944Sdim  SIZE_T n = REAL(strlen)(src);
289353944Sdim  CHECK_UNPOISONED_STRING(src + n, 0);
290353944Sdim  char *res = REAL(strcpy)(dest, src);
291353944Sdim  CopyShadowAndOrigin(dest, src, n + 1, &stack);
292353944Sdim  return res;
293353944Sdim}
294353944Sdim
295353944SdimINTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) {
296353944Sdim  ENSURE_MSAN_INITED();
297353944Sdim  GET_STORE_STACK_TRACE;
298353944Sdim  SIZE_T copy_size = REAL(strnlen)(src, n);
299353944Sdim  if (copy_size < n)
300353944Sdim    copy_size++;  // trailing \0
301353944Sdim  char *res = REAL(strncpy)(dest, src, n);
302353944Sdim  CopyShadowAndOrigin(dest, src, copy_size, &stack);
303353944Sdim  __msan_unpoison(dest + copy_size, n - copy_size);
304353944Sdim  return res;
305353944Sdim}
306353944Sdim
307353944Sdim#if !SANITIZER_NETBSD
308353944SdimINTERCEPTOR(char *, stpcpy, char *dest, const char *src) {
309353944Sdim  ENSURE_MSAN_INITED();
310353944Sdim  GET_STORE_STACK_TRACE;
311353944Sdim  SIZE_T n = REAL(strlen)(src);
312353944Sdim  CHECK_UNPOISONED_STRING(src + n, 0);
313353944Sdim  char *res = REAL(stpcpy)(dest, src);
314353944Sdim  CopyShadowAndOrigin(dest, src, n + 1, &stack);
315353944Sdim  return res;
316353944Sdim}
317353944Sdim#define MSAN_MAYBE_INTERCEPT_STPCPY INTERCEPT_FUNCTION(stpcpy)
318353944Sdim#else
319353944Sdim#define MSAN_MAYBE_INTERCEPT_STPCPY
320353944Sdim#endif
321353944Sdim
322353944SdimINTERCEPTOR(char *, strdup, char *src) {
323353944Sdim  ENSURE_MSAN_INITED();
324353944Sdim  GET_STORE_STACK_TRACE;
325353944Sdim  // On FreeBSD strdup() leverages strlen().
326353944Sdim  InterceptorScope interceptor_scope;
327353944Sdim  SIZE_T n = REAL(strlen)(src);
328353944Sdim  CHECK_UNPOISONED_STRING(src + n, 0);
329353944Sdim  char *res = REAL(strdup)(src);
330353944Sdim  CopyShadowAndOrigin(res, src, n + 1, &stack);
331353944Sdim  return res;
332353944Sdim}
333353944Sdim
334353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
335353944SdimINTERCEPTOR(char *, __strdup, char *src) {
336353944Sdim  ENSURE_MSAN_INITED();
337353944Sdim  GET_STORE_STACK_TRACE;
338353944Sdim  SIZE_T n = REAL(strlen)(src);
339353944Sdim  CHECK_UNPOISONED_STRING(src + n, 0);
340353944Sdim  char *res = REAL(__strdup)(src);
341353944Sdim  CopyShadowAndOrigin(res, src, n + 1, &stack);
342353944Sdim  return res;
343353944Sdim}
344353944Sdim#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
345353944Sdim#else
346353944Sdim#define MSAN_MAYBE_INTERCEPT___STRDUP
347353944Sdim#endif
348353944Sdim
349353944Sdim#if !SANITIZER_NETBSD
350353944SdimINTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
351353944Sdim  ENSURE_MSAN_INITED();
352353944Sdim  char *res = REAL(gcvt)(number, ndigit, buf);
353353944Sdim  SIZE_T n = REAL(strlen)(buf);
354353944Sdim  __msan_unpoison(buf, n + 1);
355353944Sdim  return res;
356353944Sdim}
357353944Sdim#define MSAN_MAYBE_INTERCEPT_GCVT INTERCEPT_FUNCTION(gcvt)
358353944Sdim#else
359353944Sdim#define MSAN_MAYBE_INTERCEPT_GCVT
360353944Sdim#endif
361353944Sdim
362353944SdimINTERCEPTOR(char *, strcat, char *dest, const char *src) {
363353944Sdim  ENSURE_MSAN_INITED();
364353944Sdim  GET_STORE_STACK_TRACE;
365353944Sdim  SIZE_T src_size = REAL(strlen)(src);
366353944Sdim  SIZE_T dest_size = REAL(strlen)(dest);
367353944Sdim  CHECK_UNPOISONED_STRING(src + src_size, 0);
368353944Sdim  CHECK_UNPOISONED_STRING(dest + dest_size, 0);
369353944Sdim  char *res = REAL(strcat)(dest, src);
370353944Sdim  CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
371353944Sdim  return res;
372353944Sdim}
373353944Sdim
374353944SdimINTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) {
375353944Sdim  ENSURE_MSAN_INITED();
376353944Sdim  GET_STORE_STACK_TRACE;
377353944Sdim  SIZE_T dest_size = REAL(strlen)(dest);
378353944Sdim  SIZE_T copy_size = REAL(strnlen)(src, n);
379353944Sdim  CHECK_UNPOISONED_STRING(dest + dest_size, 0);
380353944Sdim  char *res = REAL(strncat)(dest, src, n);
381353944Sdim  CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
382353944Sdim  __msan_unpoison(dest + dest_size + copy_size, 1); // \0
383353944Sdim  return res;
384353944Sdim}
385353944Sdim
386353944Sdim// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
387353944Sdim// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
388353944Sdim#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
389353944Sdim  ENSURE_MSAN_INITED();                             \
390353944Sdim  ret_type res = REAL(func)(__VA_ARGS__);           \
391353944Sdim  __msan_unpoison(endptr, sizeof(*endptr));         \
392353944Sdim  return res;
393353944Sdim
394353944Sdim#define INTERCEPTOR_STRTO(ret_type, func, char_type)                       \
395353944Sdim  INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
396353944Sdim    INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr);                  \
397353944Sdim  }
398353944Sdim
399353944Sdim#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)                \
400353944Sdim  INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
401353944Sdim              int base) {                                                \
402353944Sdim    INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base);          \
403353944Sdim  }
404353944Sdim
405353944Sdim#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type)                 \
406353944Sdim  INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
407353944Sdim              void *loc) {                                               \
408353944Sdim    INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc);           \
409353944Sdim  }
410353944Sdim
411353944Sdim#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type)            \
412353944Sdim  INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
413353944Sdim              int base, void *loc) {                                     \
414353944Sdim    INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc);     \
415353944Sdim  }
416353944Sdim
417353944Sdim#if SANITIZER_NETBSD
418353944Sdim#define INTERCEPTORS_STRTO(ret_type, func, char_type)      \
419353944Sdim  INTERCEPTOR_STRTO(ret_type, func, char_type)             \
420353944Sdim  INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type)
421353944Sdim
422353944Sdim#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type)      \
423353944Sdim  INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)             \
424353944Sdim  INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type)
425353944Sdim
426353944Sdim#else
427353944Sdim#define INTERCEPTORS_STRTO(ret_type, func, char_type)      \
428353944Sdim  INTERCEPTOR_STRTO(ret_type, func, char_type)             \
429353944Sdim  INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type)     \
430353944Sdim  INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
431353944Sdim  INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
432353944Sdim
433353944Sdim#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type)      \
434353944Sdim  INTERCEPTOR_STRTO_BASE(ret_type, func, char_type)             \
435353944Sdim  INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type)     \
436353944Sdim  INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
437353944Sdim  INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
438353944Sdim#endif
439353944Sdim
440353944SdimINTERCEPTORS_STRTO(double, strtod, char)
441353944SdimINTERCEPTORS_STRTO(float, strtof, char)
442353944SdimINTERCEPTORS_STRTO(long double, strtold, char)
443353944SdimINTERCEPTORS_STRTO_BASE(long, strtol, char)
444353944SdimINTERCEPTORS_STRTO_BASE(long long, strtoll, char)
445353944SdimINTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char)
446353944SdimINTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char)
447353944SdimINTERCEPTORS_STRTO_BASE(u64, strtouq, char)
448353944Sdim
449353944SdimINTERCEPTORS_STRTO(double, wcstod, wchar_t)
450353944SdimINTERCEPTORS_STRTO(float, wcstof, wchar_t)
451353944SdimINTERCEPTORS_STRTO(long double, wcstold, wchar_t)
452353944SdimINTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t)
453353944SdimINTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t)
454353944SdimINTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t)
455353944SdimINTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t)
456353944Sdim
457353944Sdim#if SANITIZER_NETBSD
458353944Sdim#define INTERCEPT_STRTO(func) \
459353944Sdim  INTERCEPT_FUNCTION(func); \
460353944Sdim  INTERCEPT_FUNCTION(func##_l);
461353944Sdim#else
462353944Sdim#define INTERCEPT_STRTO(func) \
463353944Sdim  INTERCEPT_FUNCTION(func); \
464353944Sdim  INTERCEPT_FUNCTION(func##_l); \
465353944Sdim  INTERCEPT_FUNCTION(__##func##_l); \
466353944Sdim  INTERCEPT_FUNCTION(__##func##_internal);
467353944Sdim#endif
468353944Sdim
469353944Sdim
470353944Sdim// FIXME: support *wprintf in common format interceptors.
471353944SdimINTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
472353944Sdim  ENSURE_MSAN_INITED();
473353944Sdim  int res = REAL(vswprintf)(str, size, format, ap);
474353944Sdim  if (res >= 0) {
475353944Sdim    __msan_unpoison(str, 4 * (res + 1));
476353944Sdim  }
477353944Sdim  return res;
478353944Sdim}
479353944Sdim
480353944SdimINTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
481353944Sdim  ENSURE_MSAN_INITED();
482353944Sdim  va_list ap;
483353944Sdim  va_start(ap, format);
484353944Sdim  int res = vswprintf(str, size, format, ap);
485353944Sdim  va_end(ap);
486353944Sdim  return res;
487353944Sdim}
488353944Sdim
489353944Sdim#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
490353944Sdim  ENSURE_MSAN_INITED();                                              \
491353944Sdim  InterceptorScope interceptor_scope;                                \
492353944Sdim  ret_type res = REAL(func)(s, __VA_ARGS__);                         \
493353944Sdim  if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1));          \
494353944Sdim  return res;
495353944Sdim
496353944SdimINTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
497353944Sdim            __sanitizer_tm *tm) {
498353944Sdim  INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
499353944Sdim}
500353944Sdim
501353944SdimINTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
502353944Sdim            __sanitizer_tm *tm, void *loc) {
503353944Sdim  INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
504353944Sdim}
505353944Sdim
506353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
507353944SdimINTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
508353944Sdim            __sanitizer_tm *tm, void *loc) {
509353944Sdim  INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
510353944Sdim                            loc);
511353944Sdim}
512353944Sdim#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
513353944Sdim#else
514353944Sdim#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
515353944Sdim#endif
516353944Sdim
517353944SdimINTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
518353944Sdim            __sanitizer_tm *tm) {
519353944Sdim  INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
520353944Sdim}
521353944Sdim
522353944SdimINTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
523353944Sdim            __sanitizer_tm *tm, void *loc) {
524353944Sdim  INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
525353944Sdim                            loc);
526353944Sdim}
527353944Sdim
528353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
529353944SdimINTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
530353944Sdim            __sanitizer_tm *tm, void *loc) {
531353944Sdim  INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
532353944Sdim                            loc);
533353944Sdim}
534353944Sdim#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
535353944Sdim#else
536353944Sdim#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
537353944Sdim#endif
538353944Sdim
539353944SdimINTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
540353944Sdim  ENSURE_MSAN_INITED();
541353944Sdim  int res = REAL(mbtowc)(dest, src, n);
542353944Sdim  if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
543353944Sdim  return res;
544353944Sdim}
545353944Sdim
546353944SdimINTERCEPTOR(SIZE_T, mbrtowc, wchar_t *dest, const char *src, SIZE_T n,
547353944Sdim            void *ps) {
548353944Sdim  ENSURE_MSAN_INITED();
549353944Sdim  SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
550353944Sdim  if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
551353944Sdim  return res;
552353944Sdim}
553353944Sdim
554353944Sdim// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
555353944SdimINTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
556353944Sdim  ENSURE_MSAN_INITED();
557353944Sdim  GET_STORE_STACK_TRACE;
558353944Sdim  wchar_t *res = REAL(wmemcpy)(dest, src, n);
559353944Sdim  CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
560353944Sdim  return res;
561353944Sdim}
562353944Sdim
563353944Sdim#if !SANITIZER_NETBSD
564353944SdimINTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
565353944Sdim  ENSURE_MSAN_INITED();
566353944Sdim  GET_STORE_STACK_TRACE;
567353944Sdim  wchar_t *res = REAL(wmempcpy)(dest, src, n);
568353944Sdim  CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
569353944Sdim  return res;
570353944Sdim}
571353944Sdim#define MSAN_MAYBE_INTERCEPT_WMEMPCPY INTERCEPT_FUNCTION(wmempcpy)
572353944Sdim#else
573353944Sdim#define MSAN_MAYBE_INTERCEPT_WMEMPCPY
574353944Sdim#endif
575353944Sdim
576353944SdimINTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
577353944Sdim  CHECK(MEM_IS_APP(s));
578353944Sdim  ENSURE_MSAN_INITED();
579353944Sdim  wchar_t *res = REAL(wmemset)(s, c, n);
580353944Sdim  __msan_unpoison(s, n * sizeof(wchar_t));
581353944Sdim  return res;
582353944Sdim}
583353944Sdim
584353944SdimINTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
585353944Sdim  ENSURE_MSAN_INITED();
586353944Sdim  GET_STORE_STACK_TRACE;
587353944Sdim  wchar_t *res = REAL(wmemmove)(dest, src, n);
588353944Sdim  MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
589353944Sdim  return res;
590353944Sdim}
591353944Sdim
592353944SdimINTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
593353944Sdim  ENSURE_MSAN_INITED();
594353944Sdim  int res = REAL(wcscmp)(s1, s2);
595353944Sdim  return res;
596353944Sdim}
597353944Sdim
598353944SdimINTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
599353944Sdim  ENSURE_MSAN_INITED();
600353944Sdim  int res = REAL(gettimeofday)(tv, tz);
601353944Sdim  if (tv)
602353944Sdim    __msan_unpoison(tv, 16);
603353944Sdim  if (tz)
604353944Sdim    __msan_unpoison(tz, 8);
605353944Sdim  return res;
606353944Sdim}
607353944Sdim
608353944Sdim#if !SANITIZER_NETBSD
609353944SdimINTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
610353944Sdim  ENSURE_MSAN_INITED();
611353944Sdim  char *res = REAL(fcvt)(x, a, b, c);
612353944Sdim  __msan_unpoison(b, sizeof(*b));
613353944Sdim  __msan_unpoison(c, sizeof(*c));
614353944Sdim  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
615353944Sdim  return res;
616353944Sdim}
617353944Sdim#define MSAN_MAYBE_INTERCEPT_FCVT INTERCEPT_FUNCTION(fcvt)
618353944Sdim#else
619353944Sdim#define MSAN_MAYBE_INTERCEPT_FCVT
620353944Sdim#endif
621353944Sdim
622353944SdimINTERCEPTOR(char *, getenv, char *name) {
623353944Sdim  if (msan_init_is_running)
624353944Sdim    return REAL(getenv)(name);
625353944Sdim  ENSURE_MSAN_INITED();
626353944Sdim  char *res = REAL(getenv)(name);
627353944Sdim  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
628353944Sdim  return res;
629353944Sdim}
630353944Sdim
631353944Sdimextern char **environ;
632353944Sdim
633353944Sdimstatic void UnpoisonEnviron() {
634353944Sdim  char **envp = environ;
635353944Sdim  for (; *envp; ++envp) {
636353944Sdim    __msan_unpoison(envp, sizeof(*envp));
637353944Sdim    __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
638353944Sdim  }
639353944Sdim  // Trailing NULL pointer.
640353944Sdim  __msan_unpoison(envp, sizeof(*envp));
641353944Sdim}
642353944Sdim
643353944SdimINTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
644353944Sdim  ENSURE_MSAN_INITED();
645353944Sdim  CHECK_UNPOISONED_STRING(name, 0);
646353944Sdim  int res = REAL(setenv)(name, value, overwrite);
647353944Sdim  if (!res) UnpoisonEnviron();
648353944Sdim  return res;
649353944Sdim}
650353944Sdim
651353944SdimINTERCEPTOR(int, putenv, char *string) {
652353944Sdim  ENSURE_MSAN_INITED();
653353944Sdim  int res = REAL(putenv)(string);
654353944Sdim  if (!res) UnpoisonEnviron();
655353944Sdim  return res;
656353944Sdim}
657353944Sdim
658353944Sdim#if SANITIZER_FREEBSD || SANITIZER_NETBSD
659353944SdimINTERCEPTOR(int, fstat, int fd, void *buf) {
660353944Sdim  ENSURE_MSAN_INITED();
661353944Sdim  int res = REAL(fstat)(fd, buf);
662353944Sdim  if (!res)
663353944Sdim    __msan_unpoison(buf, __sanitizer::struct_stat_sz);
664353944Sdim  return res;
665353944Sdim}
666353944Sdim#define MSAN_MAYBE_INTERCEPT_FSTAT INTERCEPT_FUNCTION(fstat)
667353944Sdim#else
668353944Sdim#define MSAN_MAYBE_INTERCEPT_FSTAT
669353944Sdim#endif
670353944Sdim
671353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
672353944SdimINTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
673353944Sdim  ENSURE_MSAN_INITED();
674353944Sdim  int res = REAL(__fxstat)(magic, fd, buf);
675353944Sdim  if (!res)
676353944Sdim    __msan_unpoison(buf, __sanitizer::struct_stat_sz);
677353944Sdim  return res;
678353944Sdim}
679353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat)
680353944Sdim#else
681353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTAT
682353944Sdim#endif
683353944Sdim
684353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
685353944SdimINTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
686353944Sdim  ENSURE_MSAN_INITED();
687353944Sdim  int res = REAL(__fxstat64)(magic, fd, buf);
688353944Sdim  if (!res)
689353944Sdim    __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
690353944Sdim  return res;
691353944Sdim}
692353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64)
693353944Sdim#else
694353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTAT64
695353944Sdim#endif
696353944Sdim
697353944Sdim#if SANITIZER_FREEBSD || SANITIZER_NETBSD
698353944SdimINTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) {
699353944Sdim  ENSURE_MSAN_INITED();
700353944Sdim  int res = REAL(fstatat)(fd, pathname, buf, flags);
701353944Sdim  if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
702353944Sdim  return res;
703353944Sdim}
704353944Sdim# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(fstatat)
705353944Sdim#else
706353944SdimINTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
707353944Sdim            int flags) {
708353944Sdim  ENSURE_MSAN_INITED();
709353944Sdim  int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
710353944Sdim  if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
711353944Sdim  return res;
712353944Sdim}
713353944Sdim# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(__fxstatat)
714353944Sdim#endif
715353944Sdim
716353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
717353944SdimINTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
718353944Sdim            int flags) {
719353944Sdim  ENSURE_MSAN_INITED();
720353944Sdim  int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
721353944Sdim  if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
722353944Sdim  return res;
723353944Sdim}
724353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64)
725353944Sdim#else
726353944Sdim#define MSAN_MAYBE_INTERCEPT___FXSTATAT64
727353944Sdim#endif
728353944Sdim
729353944SdimINTERCEPTOR(int, pipe, int pipefd[2]) {
730353944Sdim  if (msan_init_is_running)
731353944Sdim    return REAL(pipe)(pipefd);
732353944Sdim  ENSURE_MSAN_INITED();
733353944Sdim  int res = REAL(pipe)(pipefd);
734353944Sdim  if (!res)
735353944Sdim    __msan_unpoison(pipefd, sizeof(int[2]));
736353944Sdim  return res;
737353944Sdim}
738353944Sdim
739353944SdimINTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
740353944Sdim  ENSURE_MSAN_INITED();
741353944Sdim  int res = REAL(pipe2)(pipefd, flags);
742353944Sdim  if (!res)
743353944Sdim    __msan_unpoison(pipefd, sizeof(int[2]));
744353944Sdim  return res;
745353944Sdim}
746353944Sdim
747353944SdimINTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
748353944Sdim  ENSURE_MSAN_INITED();
749353944Sdim  int res = REAL(socketpair)(domain, type, protocol, sv);
750353944Sdim  if (!res)
751353944Sdim    __msan_unpoison(sv, sizeof(int[2]));
752353944Sdim  return res;
753353944Sdim}
754353944Sdim
755353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
756353944SdimINTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
757353944Sdim  ENSURE_MSAN_INITED();
758353944Sdim  char *res = REAL(fgets_unlocked)(s, size, stream);
759353944Sdim  if (res)
760353944Sdim    __msan_unpoison(s, REAL(strlen)(s) + 1);
761353944Sdim  return res;
762353944Sdim}
763353944Sdim#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
764353944Sdim#else
765353944Sdim#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
766353944Sdim#endif
767353944Sdim
768353944Sdim#define INTERCEPTOR_GETRLIMIT_BODY(func, resource, rlim)  \
769353944Sdim  if (msan_init_is_running)                               \
770353944Sdim    return REAL(getrlimit)(resource, rlim);               \
771353944Sdim  ENSURE_MSAN_INITED();                                   \
772353944Sdim  int res = REAL(func)(resource, rlim);                   \
773353944Sdim  if (!res)                                               \
774353944Sdim    __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz); \
775353944Sdim  return res
776353944Sdim
777353944SdimINTERCEPTOR(int, getrlimit, int resource, void *rlim) {
778353944Sdim  INTERCEPTOR_GETRLIMIT_BODY(getrlimit, resource, rlim);
779353944Sdim}
780353944Sdim
781353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
782353944SdimINTERCEPTOR(int, __getrlimit, int resource, void *rlim) {
783353944Sdim  INTERCEPTOR_GETRLIMIT_BODY(__getrlimit, resource, rlim);
784353944Sdim}
785353944Sdim
786353944SdimINTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
787353944Sdim  if (msan_init_is_running) return REAL(getrlimit64)(resource, rlim);
788353944Sdim  ENSURE_MSAN_INITED();
789353944Sdim  int res = REAL(getrlimit64)(resource, rlim);
790353944Sdim  if (!res) __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
791353944Sdim  return res;
792353944Sdim}
793353944Sdim
794353944SdimINTERCEPTOR(int, prlimit, int pid, int resource, void *new_rlimit,
795353944Sdim            void *old_rlimit) {
796353944Sdim  if (msan_init_is_running)
797353944Sdim    return REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
798353944Sdim  ENSURE_MSAN_INITED();
799353944Sdim  CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit_sz);
800353944Sdim  int res = REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
801353944Sdim  if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit_sz);
802353944Sdim  return res;
803353944Sdim}
804353944Sdim
805353944SdimINTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit,
806353944Sdim            void *old_rlimit) {
807353944Sdim  if (msan_init_is_running)
808353944Sdim    return REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
809353944Sdim  ENSURE_MSAN_INITED();
810353944Sdim  CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit64_sz);
811353944Sdim  int res = REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
812353944Sdim  if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit64_sz);
813353944Sdim  return res;
814353944Sdim}
815353944Sdim
816353944Sdim#define MSAN_MAYBE_INTERCEPT___GETRLIMIT INTERCEPT_FUNCTION(__getrlimit)
817353944Sdim#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
818353944Sdim#define MSAN_MAYBE_INTERCEPT_PRLIMIT INTERCEPT_FUNCTION(prlimit)
819353944Sdim#define MSAN_MAYBE_INTERCEPT_PRLIMIT64 INTERCEPT_FUNCTION(prlimit64)
820353944Sdim#else
821353944Sdim#define MSAN_MAYBE_INTERCEPT___GETRLIMIT
822353944Sdim#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
823353944Sdim#define MSAN_MAYBE_INTERCEPT_PRLIMIT
824353944Sdim#define MSAN_MAYBE_INTERCEPT_PRLIMIT64
825353944Sdim#endif
826353944Sdim
827353944Sdim#if SANITIZER_FREEBSD
828353944Sdim// FreeBSD's <sys/utsname.h> define uname() as
829353944Sdim// static __inline int uname(struct utsname *name) {
830353944Sdim//   return __xuname(SYS_NMLN, (void*)name);
831353944Sdim// }
832353944SdimINTERCEPTOR(int, __xuname, int size, void *utsname) {
833353944Sdim  ENSURE_MSAN_INITED();
834353944Sdim  int res = REAL(__xuname)(size, utsname);
835353944Sdim  if (!res)
836353944Sdim    __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
837353944Sdim  return res;
838353944Sdim}
839353944Sdim#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname)
840353944Sdim#else
841353944SdimINTERCEPTOR(int, uname, struct utsname *utsname) {
842353944Sdim  ENSURE_MSAN_INITED();
843353944Sdim  int res = REAL(uname)(utsname);
844353944Sdim  if (!res)
845353944Sdim    __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
846353944Sdim  return res;
847353944Sdim}
848353944Sdim#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname)
849353944Sdim#endif
850353944Sdim
851353944SdimINTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
852353944Sdim  ENSURE_MSAN_INITED();
853353944Sdim  int res = REAL(gethostname)(name, len);
854353944Sdim  if (!res) {
855353944Sdim    SIZE_T real_len = REAL(strnlen)(name, len);
856353944Sdim    if (real_len < len)
857353944Sdim      ++real_len;
858353944Sdim    __msan_unpoison(name, real_len);
859353944Sdim  }
860353944Sdim  return res;
861353944Sdim}
862353944Sdim
863353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
864353944SdimINTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
865353944Sdim    int timeout) {
866353944Sdim  ENSURE_MSAN_INITED();
867353944Sdim  int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
868353944Sdim  if (res > 0) {
869353944Sdim    __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
870353944Sdim  }
871353944Sdim  return res;
872353944Sdim}
873353944Sdim#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
874353944Sdim#else
875353944Sdim#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
876353944Sdim#endif
877353944Sdim
878353944Sdim#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
879353944SdimINTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
880353944Sdim    int timeout, void *sigmask) {
881353944Sdim  ENSURE_MSAN_INITED();
882353944Sdim  int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
883353944Sdim  if (res > 0) {
884353944Sdim    __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
885353944Sdim  }
886353944Sdim  return res;
887353944Sdim}
888353944Sdim#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
889353944Sdim#else
890353944Sdim#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
891353944Sdim#endif
892353944Sdim
893353944SdimINTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
894353944Sdim  GET_MALLOC_STACK_TRACE;
895353944Sdim  if (UNLIKELY(!msan_inited))
896353944Sdim    // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
897353944Sdim    return AllocateFromLocalPool(nmemb * size);
898353944Sdim  return msan_calloc(nmemb, size, &stack);
899353944Sdim}
900353944Sdim
901353944SdimINTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
902353944Sdim  GET_MALLOC_STACK_TRACE;
903353944Sdim  if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
904353944Sdim    uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
905353944Sdim    uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
906353944Sdim    void *new_ptr;
907353944Sdim    if (UNLIKELY(!msan_inited)) {
908353944Sdim      new_ptr = AllocateFromLocalPool(copy_size);
909353944Sdim    } else {
910353944Sdim      copy_size = size;
911353944Sdim      new_ptr = msan_malloc(copy_size, &stack);
912353944Sdim    }
913353944Sdim    internal_memcpy(new_ptr, ptr, copy_size);
914353944Sdim    return new_ptr;
915353944Sdim  }
916353944Sdim  return msan_realloc(ptr, size, &stack);
917353944Sdim}
918353944Sdim
919353944SdimINTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) {
920353944Sdim  GET_MALLOC_STACK_TRACE;
921353944Sdim  return msan_reallocarray(ptr, nmemb, size, &stack);
922353944Sdim}
923353944Sdim
924353944SdimINTERCEPTOR(void *, malloc, SIZE_T size) {
925353944Sdim  GET_MALLOC_STACK_TRACE;
926353944Sdim  if (UNLIKELY(!msan_inited))
927353944Sdim    // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
928353944Sdim    return AllocateFromLocalPool(size);
929353944Sdim  return msan_malloc(size, &stack);
930353944Sdim}
931353944Sdim
932353944Sdimvoid __msan_allocated_memory(const void *data, uptr size) {
933353944Sdim  GET_MALLOC_STACK_TRACE;
934353944Sdim  if (flags()->poison_in_malloc) {
935353944Sdim    stack.tag = STACK_TRACE_TAG_POISON;
936353944Sdim    PoisonMemory(data, size, &stack);
937353944Sdim  }
938353944Sdim}
939353944Sdim
940353944Sdimvoid __msan_copy_shadow(void *dest, const void *src, uptr n) {
941353944Sdim  GET_STORE_STACK_TRACE;
942353944Sdim  MoveShadowAndOrigin(dest, src, n, &stack);
943353944Sdim}
944353944Sdim
945353944Sdimvoid __sanitizer_dtor_callback(const void *data, uptr size) {
946353944Sdim  GET_MALLOC_STACK_TRACE;
947353944Sdim  if (flags()->poison_in_dtor) {
948353944Sdim    stack.tag = STACK_TRACE_TAG_POISON;
949353944Sdim    PoisonMemory(data, size, &stack);
950353944Sdim  }
951353944Sdim}
952353944Sdim
953353944Sdimtemplate <class Mmap>
954353944Sdimstatic void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
955353944Sdim                              int prot, int flags, int fd, OFF64_T offset) {
956353944Sdim  if (addr && !MEM_IS_APP(addr)) {
957353944Sdim    if (flags & map_fixed) {
958353944Sdim      errno = errno_EINVAL;
959353944Sdim      return (void *)-1;
960353944Sdim    } else {
961353944Sdim      addr = nullptr;
962353944Sdim    }
963353944Sdim  }
964353944Sdim  void *res = real_mmap(addr, length, prot, flags, fd, offset);
965353944Sdim  if (res != (void *)-1) __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
966353944Sdim  return res;
967353944Sdim}
968353944Sdim
969353944SdimINTERCEPTOR(int, getrusage, int who, void *usage) {
970353944Sdim  ENSURE_MSAN_INITED();
971353944Sdim  int res = REAL(getrusage)(who, usage);
972353944Sdim  if (res == 0) {
973353944Sdim    __msan_unpoison(usage, __sanitizer::struct_rusage_sz);
974353944Sdim  }
975353944Sdim  return res;
976353944Sdim}
977353944Sdim
978353944Sdimclass SignalHandlerScope {
979353944Sdim public:
980353944Sdim  SignalHandlerScope() {
981353944Sdim    if (MsanThread *t = GetCurrentThread())
982353944Sdim      t->EnterSignalHandler();
983353944Sdim  }
984353944Sdim  ~SignalHandlerScope() {
985353944Sdim    if (MsanThread *t = GetCurrentThread())
986353944Sdim      t->LeaveSignalHandler();
987353944Sdim  }
988353944Sdim};
989353944Sdim
990353944Sdim// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
991353944Sdim// Access to sigactions[] is gone with relaxed atomics to avoid data race with
992353944Sdim// the signal handler.
993353944Sdimconst int kMaxSignals = 1024;
994353944Sdimstatic atomic_uintptr_t sigactions[kMaxSignals];
995353944Sdimstatic StaticSpinMutex sigactions_mu;
996353944Sdim
997353944Sdimstatic void SignalHandler(int signo) {
998353944Sdim  SignalHandlerScope signal_handler_scope;
999353944Sdim  ScopedThreadLocalStateBackup stlsb;
1000353944Sdim  UnpoisonParam(1);
1001353944Sdim
1002353944Sdim  typedef void (*signal_cb)(int x);
1003353944Sdim  signal_cb cb =
1004353944Sdim      (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1005353944Sdim  cb(signo);
1006353944Sdim}
1007353944Sdim
1008353944Sdimstatic void SignalAction(int signo, void *si, void *uc) {
1009353944Sdim  SignalHandlerScope signal_handler_scope;
1010353944Sdim  ScopedThreadLocalStateBackup stlsb;
1011353944Sdim  UnpoisonParam(3);
1012353944Sdim  __msan_unpoison(si, sizeof(__sanitizer_sigaction));
1013353944Sdim  __msan_unpoison(uc, __sanitizer::ucontext_t_sz);
1014353944Sdim
1015353944Sdim  typedef void (*sigaction_cb)(int, void *, void *);
1016353944Sdim  sigaction_cb cb =
1017353944Sdim      (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1018353944Sdim  cb(signo, si, uc);
1019353944Sdim}
1020353944Sdim
1021353944Sdimstatic void read_sigaction(const __sanitizer_sigaction *act) {
1022353944Sdim  CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags));
1023353944Sdim  if (act->sa_flags & __sanitizer::sa_siginfo)
1024353944Sdim    CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction));
1025353944Sdim  else
1026353944Sdim    CHECK_UNPOISONED(&act->handler, sizeof(act->handler));
1027353944Sdim  CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask));
1028353944Sdim}
1029353944Sdim
1030353944Sdimextern "C" int pthread_attr_init(void *attr);
1031353944Sdimextern "C" int pthread_attr_destroy(void *attr);
1032353944Sdim
1033353944Sdimstatic void *MsanThreadStartFunc(void *arg) {
1034353944Sdim  MsanThread *t = (MsanThread *)arg;
1035353944Sdim  SetCurrentThread(t);
1036353944Sdim  return t->ThreadStart();
1037353944Sdim}
1038353944Sdim
1039353944SdimINTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
1040353944Sdim            void * param) {
1041353944Sdim  ENSURE_MSAN_INITED(); // for GetTlsSize()
1042353944Sdim  __sanitizer_pthread_attr_t myattr;
1043353944Sdim  if (!attr) {
1044353944Sdim    pthread_attr_init(&myattr);
1045353944Sdim    attr = &myattr;
1046353944Sdim  }
1047353944Sdim
1048353944Sdim  AdjustStackSize(attr);
1049353944Sdim
1050353944Sdim  MsanThread *t = MsanThread::Create(callback, param);
1051353944Sdim
1052353944Sdim  int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
1053353944Sdim
1054353944Sdim  if (attr == &myattr)
1055353944Sdim    pthread_attr_destroy(&myattr);
1056353944Sdim  if (!res) {
1057353944Sdim    __msan_unpoison(th, __sanitizer::pthread_t_sz);
1058353944Sdim  }
1059353944Sdim  return res;
1060353944Sdim}
1061353944Sdim
1062353944SdimINTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
1063353944Sdim            void (*dtor)(void *value)) {
1064353944Sdim  if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
1065353944Sdim  ENSURE_MSAN_INITED();
1066353944Sdim  int res = REAL(pthread_key_create)(key, dtor);
1067353944Sdim  if (!res && key)
1068353944Sdim    __msan_unpoison(key, sizeof(*key));
1069353944Sdim  return res;
1070353944Sdim}
1071353944Sdim
1072353944Sdim#if SANITIZER_NETBSD
1073357095SdimINTERCEPTOR(int, __libc_thr_keycreate, __sanitizer_pthread_key_t *m,
1074357095Sdim            void (*dtor)(void *value))
1075357095SdimALIAS(WRAPPER_NAME(pthread_key_create));
1076353944Sdim#endif
1077353944Sdim
1078353944SdimINTERCEPTOR(int, pthread_join, void *th, void **retval) {
1079353944Sdim  ENSURE_MSAN_INITED();
1080353944Sdim  int res = REAL(pthread_join)(th, retval);
1081353944Sdim  if (!res && retval)
1082353944Sdim    __msan_unpoison(retval, sizeof(*retval));
1083353944Sdim  return res;
1084353944Sdim}
1085353944Sdim
1086353944Sdimextern char *tzname[2];
1087353944Sdim
1088353944SdimINTERCEPTOR(void, tzset, int fake) {
1089353944Sdim  ENSURE_MSAN_INITED();
1090353944Sdim  InterceptorScope interceptor_scope;
1091353944Sdim  REAL(tzset)(fake);
1092353944Sdim  if (tzname[0])
1093353944Sdim    __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
1094353944Sdim  if (tzname[1])
1095353944Sdim    __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1);
1096353944Sdim  return;
1097353944Sdim}
1098353944Sdim
1099353944Sdimstruct MSanAtExitRecord {
1100353944Sdim  void (*func)(void *arg);
1101353944Sdim  void *arg;
1102353944Sdim};
1103353944Sdim
1104353944Sdimstruct InterceptorContext {
1105353944Sdim  BlockingMutex atexit_mu;
1106353944Sdim  Vector<struct MSanAtExitRecord *> AtExitStack;
1107353944Sdim
1108353944Sdim  InterceptorContext()
1109353944Sdim      : AtExitStack() {
1110353944Sdim  }
1111353944Sdim};
1112353944Sdim
1113353944Sdimstatic ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
1114353944SdimInterceptorContext *interceptor_ctx() {
1115353944Sdim  return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
1116353944Sdim}
1117353944Sdim
1118353944Sdimvoid MSanAtExitWrapper() {
1119353944Sdim  MSanAtExitRecord *r;
1120353944Sdim  {
1121353944Sdim    BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
1122353944Sdim
1123353944Sdim    uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
1124353944Sdim    r = interceptor_ctx()->AtExitStack[element];
1125353944Sdim    interceptor_ctx()->AtExitStack.PopBack();
1126353944Sdim  }
1127353944Sdim
1128353944Sdim  UnpoisonParam(1);
1129353944Sdim  ((void(*)())r->func)();
1130353944Sdim  InternalFree(r);
1131353944Sdim}
1132353944Sdim
1133353944Sdimvoid MSanCxaAtExitWrapper(void *arg) {
1134353944Sdim  UnpoisonParam(1);
1135353944Sdim  MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
1136353944Sdim  // libc before 2.27 had race which caused occasional double handler execution
1137353944Sdim  // https://sourceware.org/ml/libc-alpha/2017-08/msg01204.html
1138353944Sdim  if (!r->func)
1139353944Sdim    return;
1140353944Sdim  r->func(r->arg);
1141353944Sdim  r->func = nullptr;
1142353944Sdim}
1143353944Sdim
1144353944Sdimstatic int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso);
1145353944Sdim
1146353944Sdim// Unpoison argument shadow for C++ module destructors.
1147353944SdimINTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
1148353944Sdim            void *dso_handle) {
1149353944Sdim  if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
1150353944Sdim  return setup_at_exit_wrapper((void(*)())func, arg, dso_handle);
1151353944Sdim}
1152353944Sdim
1153353944Sdim// Unpoison argument shadow for C++ module destructors.
1154353944SdimINTERCEPTOR(int, atexit, void (*func)()) {
1155353944Sdim  // Avoid calling real atexit as it is unrechable on at least on Linux.
1156353944Sdim  if (msan_init_is_running)
1157353944Sdim    return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0);
1158353944Sdim  return setup_at_exit_wrapper((void(*)())func, 0, 0);
1159353944Sdim}
1160353944Sdim
1161353944Sdimstatic int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
1162353944Sdim  ENSURE_MSAN_INITED();
1163353944Sdim  MSanAtExitRecord *r =
1164353944Sdim      (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
1165353944Sdim  r->func = (void(*)(void *a))f;
1166353944Sdim  r->arg = arg;
1167353944Sdim  int res;
1168353944Sdim  if (!dso) {
1169353944Sdim    // NetBSD does not preserve the 2nd argument if dso is equal to 0
1170353944Sdim    // Store ctx in a local stack-like structure
1171353944Sdim
1172353944Sdim    BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
1173353944Sdim
1174353944Sdim    res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0);
1175353944Sdim    if (!res) {
1176353944Sdim      interceptor_ctx()->AtExitStack.PushBack(r);
1177353944Sdim    }
1178353944Sdim  } else {
1179353944Sdim    res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso);
1180353944Sdim  }
1181353944Sdim  return res;
1182353944Sdim}
1183353944Sdim
1184353944Sdimstatic void BeforeFork() {
1185353944Sdim  StackDepotLockAll();
1186353944Sdim  ChainedOriginDepotLockAll();
1187353944Sdim}
1188353944Sdim
1189353944Sdimstatic void AfterFork() {
1190353944Sdim  ChainedOriginDepotUnlockAll();
1191353944Sdim  StackDepotUnlockAll();
1192353944Sdim}
1193353944Sdim
1194353944SdimINTERCEPTOR(int, fork, void) {
1195353944Sdim  ENSURE_MSAN_INITED();
1196353944Sdim  BeforeFork();
1197353944Sdim  int pid = REAL(fork)();
1198353944Sdim  AfterFork();
1199353944Sdim  return pid;
1200353944Sdim}
1201353944Sdim
1202353944Sdim// NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly
1203353944Sdim// with MSan.
1204353944Sdim#if SANITIZER_LINUX
1205353944SdimINTERCEPTOR(int, openpty, int *aparent, int *aworker, char *name,
1206353944Sdim            const void *termp, const void *winp) {
1207353944Sdim  ENSURE_MSAN_INITED();
1208353944Sdim  InterceptorScope interceptor_scope;
1209353944Sdim  int res = REAL(openpty)(aparent, aworker, name, termp, winp);
1210353944Sdim  if (!res) {
1211353944Sdim    __msan_unpoison(aparent, sizeof(*aparent));
1212353944Sdim    __msan_unpoison(aworker, sizeof(*aworker));
1213353944Sdim  }
1214353944Sdim  return res;
1215353944Sdim}
1216353944Sdim#define MSAN_MAYBE_INTERCEPT_OPENPTY INTERCEPT_FUNCTION(openpty)
1217353944Sdim#else
1218353944Sdim#define MSAN_MAYBE_INTERCEPT_OPENPTY
1219353944Sdim#endif
1220353944Sdim
1221353944Sdim// NetBSD ships with forkpty(3) in -lutil, that needs to be prebuilt explicitly
1222353944Sdim// with MSan.
1223353944Sdim#if SANITIZER_LINUX
1224353944SdimINTERCEPTOR(int, forkpty, int *aparent, char *name, const void *termp,
1225353944Sdim            const void *winp) {
1226353944Sdim  ENSURE_MSAN_INITED();
1227353944Sdim  InterceptorScope interceptor_scope;
1228353944Sdim  int res = REAL(forkpty)(aparent, name, termp, winp);
1229353944Sdim  if (res != -1)
1230353944Sdim    __msan_unpoison(aparent, sizeof(*aparent));
1231353944Sdim  return res;
1232353944Sdim}
1233353944Sdim#define MSAN_MAYBE_INTERCEPT_FORKPTY INTERCEPT_FUNCTION(forkpty)
1234353944Sdim#else
1235353944Sdim#define MSAN_MAYBE_INTERCEPT_FORKPTY
1236353944Sdim#endif
1237353944Sdim
1238353944Sdimstruct MSanInterceptorContext {
1239353944Sdim  bool in_interceptor_scope;
1240353944Sdim};
1241353944Sdim
1242353944Sdimnamespace __msan {
1243353944Sdim
1244353944Sdimint OnExit() {
1245353944Sdim  // FIXME: ask frontend whether we need to return failure.
1246353944Sdim  return 0;
1247353944Sdim}
1248353944Sdim
1249353944Sdim} // namespace __msan
1250353944Sdim
1251353944Sdim// A version of CHECK_UNPOISONED using a saved scope value. Used in common
1252353944Sdim// interceptors.
1253353944Sdim#define CHECK_UNPOISONED_CTX(ctx, x, n)                         \
1254353944Sdim  do {                                                          \
1255353944Sdim    if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
1256353944Sdim      CHECK_UNPOISONED_0(x, n);                                 \
1257353944Sdim  } while (0)
1258353944Sdim
1259353944Sdim#define MSAN_INTERCEPT_FUNC(name)                                        \
1260353944Sdim  do {                                                                   \
1261353944Sdim    if (!INTERCEPT_FUNCTION(name))                                       \
1262353944Sdim      VReport(1, "MemorySanitizer: failed to intercept '%s'\n'", #name); \
1263353944Sdim  } while (0)
1264353944Sdim
1265353944Sdim#define MSAN_INTERCEPT_FUNC_VER(name, ver)                                 \
1266353944Sdim  do {                                                                     \
1267353944Sdim    if (!INTERCEPT_FUNCTION_VER(name, ver))                                \
1268353944Sdim      VReport(1, "MemorySanitizer: failed to intercept '%s@@%s'\n", #name, \
1269353944Sdim              #ver);                                                       \
1270353944Sdim  } while (0)
1271353944Sdim
1272353944Sdim#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
1273353944Sdim#define COMMON_INTERCEPT_FUNCTION_VER(name, ver)                          \
1274353944Sdim  MSAN_INTERCEPT_FUNC_VER(name, ver)
1275353944Sdim#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count)  \
1276353944Sdim  UnpoisonParam(count)
1277353944Sdim#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
1278353944Sdim  __msan_unpoison(ptr, size)
1279353944Sdim#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
1280353944Sdim  CHECK_UNPOISONED_CTX(ctx, ptr, size)
1281353944Sdim#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
1282353944Sdim  __msan_unpoison(ptr, size)
1283353944Sdim#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)                  \
1284353944Sdim  if (msan_init_is_running) return REAL(func)(__VA_ARGS__);       \
1285353944Sdim  ENSURE_MSAN_INITED();                                           \
1286353944Sdim  MSanInterceptorContext msan_ctx = {IsInInterceptorScope()};     \
1287353944Sdim  ctx = (void *)&msan_ctx;                                        \
1288353944Sdim  (void)ctx;                                                      \
1289353944Sdim  InterceptorScope interceptor_scope;                             \
1290353944Sdim  __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */
1291353944Sdim#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
1292353944Sdim  do {                                            \
1293353944Sdim  } while (false)
1294353944Sdim#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
1295353944Sdim  do {                                         \
1296353944Sdim  } while (false)
1297353944Sdim#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
1298353944Sdim  do {                                         \
1299353944Sdim  } while (false)
1300353944Sdim#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
1301353944Sdim  do {                                                      \
1302353944Sdim  } while (false)
1303353944Sdim#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
1304353944Sdim  do {                                                \
1305353944Sdim  } while (false)  // FIXME
1306353944Sdim#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
1307353944Sdim  do {                                                         \
1308353944Sdim  } while (false)  // FIXME
1309353944Sdim#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
1310353944Sdim#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
1311353944Sdim#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)                    \
1312353944Sdim  do {                                                                         \
1313353944Sdim    link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle));                   \
1314353944Sdim    if (filename && map)                                                       \
1315353944Sdim      ForEachMappedRegion(map, __msan_unpoison);                               \
1316353944Sdim  } while (false)
1317353944Sdim
1318353944Sdim#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end)                           \
1319353944Sdim  if (MsanThread *t = GetCurrentThread()) {                                    \
1320353944Sdim    *begin = t->tls_begin();                                                   \
1321353944Sdim    *end = t->tls_end();                                                       \
1322353944Sdim  } else {                                                                     \
1323353944Sdim    *begin = *end = 0;                                                         \
1324353944Sdim  }
1325353944Sdim
1326353944Sdim#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
1327353944Sdim  {                                                         \
1328353944Sdim    (void)ctx;                                              \
1329353944Sdim    return __msan_memset(block, c, size);                   \
1330353944Sdim  }
1331353944Sdim#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
1332353944Sdim  {                                                          \
1333353944Sdim    (void)ctx;                                               \
1334353944Sdim    return __msan_memmove(to, from, size);                   \
1335353944Sdim  }
1336353944Sdim#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
1337353944Sdim  {                                                         \
1338353944Sdim    (void)ctx;                                              \
1339353944Sdim    return __msan_memcpy(to, from, size);                   \
1340353944Sdim  }
1341353944Sdim
1342353944Sdim#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \
1343353944Sdim  do {                                                      \
1344353944Sdim    GET_STORE_STACK_TRACE;                                  \
1345353944Sdim    CopyShadowAndOrigin(to, from, size, &stack);            \
1346353944Sdim    __msan_unpoison(to + size, 1);                          \
1347353944Sdim  } while (false)
1348353944Sdim
1349353944Sdim#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \
1350353944Sdim                                     offset)                                   \
1351353944Sdim  do {                                                                         \
1352353944Sdim    return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);       \
1353353944Sdim  } while (false)
1354353944Sdim
1355353944Sdim#include "sanitizer_common/sanitizer_platform_interceptors.h"
1356353944Sdim#include "sanitizer_common/sanitizer_common_interceptors.inc"
1357353944Sdim
1358353944Sdimstatic uptr signal_impl(int signo, uptr cb);
1359353944Sdimstatic int sigaction_impl(int signo, const __sanitizer_sigaction *act,
1360353944Sdim                          __sanitizer_sigaction *oldact);
1361353944Sdim
1362353944Sdim#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \
1363353944Sdim  { return sigaction_impl(signo, act, oldact); }
1364353944Sdim
1365353944Sdim#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \
1366353944Sdim  {                                                          \
1367353944Sdim    handler = signal_impl(signo, handler);                   \
1368353944Sdim    InterceptorScope interceptor_scope;                      \
1369353944Sdim    return REAL(func)(signo, handler);                       \
1370353944Sdim  }
1371353944Sdim
1372353944Sdim#include "sanitizer_common/sanitizer_signal_interceptors.inc"
1373353944Sdim
1374353944Sdimstatic int sigaction_impl(int signo, const __sanitizer_sigaction *act,
1375353944Sdim                          __sanitizer_sigaction *oldact) {
1376353944Sdim  ENSURE_MSAN_INITED();
1377353944Sdim  if (act) read_sigaction(act);
1378353944Sdim  int res;
1379353944Sdim  if (flags()->wrap_signals) {
1380353944Sdim    SpinMutexLock lock(&sigactions_mu);
1381353944Sdim    CHECK_LT(signo, kMaxSignals);
1382353944Sdim    uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
1383353944Sdim    __sanitizer_sigaction new_act;
1384353944Sdim    __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
1385353944Sdim    if (act) {
1386353944Sdim      REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
1387353944Sdim      uptr cb = (uptr)pnew_act->sigaction;
1388353944Sdim      uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
1389353944Sdim                        ? (uptr)SignalAction
1390353944Sdim                        : (uptr)SignalHandler;
1391353944Sdim      if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
1392353944Sdim        atomic_store(&sigactions[signo], cb, memory_order_relaxed);
1393353944Sdim        pnew_act->sigaction = (decltype(pnew_act->sigaction))new_cb;
1394353944Sdim      }
1395353944Sdim    }
1396353944Sdim    res = REAL(SIGACTION_SYMNAME)(signo, pnew_act, oldact);
1397353944Sdim    if (res == 0 && oldact) {
1398353944Sdim      uptr cb = (uptr)oldact->sigaction;
1399353944Sdim      if (cb == (uptr)SignalAction || cb == (uptr)SignalHandler) {
1400353944Sdim        oldact->sigaction = (decltype(oldact->sigaction))old_cb;
1401353944Sdim      }
1402353944Sdim    }
1403353944Sdim  } else {
1404353944Sdim    res = REAL(SIGACTION_SYMNAME)(signo, act, oldact);
1405353944Sdim  }
1406353944Sdim
1407353944Sdim  if (res == 0 && oldact) {
1408353944Sdim    __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
1409353944Sdim  }
1410353944Sdim  return res;
1411353944Sdim}
1412353944Sdim
1413353944Sdimstatic uptr signal_impl(int signo, uptr cb) {
1414353944Sdim  ENSURE_MSAN_INITED();
1415353944Sdim  if (flags()->wrap_signals) {
1416353944Sdim    CHECK_LT(signo, kMaxSignals);
1417353944Sdim    SpinMutexLock lock(&sigactions_mu);
1418353944Sdim    if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
1419353944Sdim      atomic_store(&sigactions[signo], cb, memory_order_relaxed);
1420353944Sdim      cb = (uptr)&SignalHandler;
1421353944Sdim    }
1422353944Sdim  }
1423353944Sdim  return cb;
1424353944Sdim}
1425353944Sdim
1426353944Sdim#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
1427353944Sdim#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
1428353944Sdim  do {                                       \
1429353944Sdim  } while (false)
1430353944Sdim#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
1431353944Sdim  do {                                       \
1432353944Sdim  } while (false)
1433353944Sdim#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
1434353944Sdim#include "sanitizer_common/sanitizer_common_syscalls.inc"
1435353944Sdim#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
1436353944Sdim
1437353944Sdimstruct dlinfo {
1438353944Sdim  char *dli_fname;
1439353944Sdim  void *dli_fbase;
1440353944Sdim  char *dli_sname;
1441353944Sdim  void *dli_saddr;
1442353944Sdim};
1443353944Sdim
1444353944SdimINTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
1445353944Sdim  void *ctx;
1446353944Sdim  COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info);
1447353944Sdim  int res = REAL(dladdr)(addr, info);
1448353944Sdim  if (res != 0) {
1449353944Sdim    __msan_unpoison(info, sizeof(*info));
1450353944Sdim    if (info->dli_fname)
1451353944Sdim      __msan_unpoison(info->dli_fname, REAL(strlen)(info->dli_fname) + 1);
1452353944Sdim    if (info->dli_sname)
1453353944Sdim      __msan_unpoison(info->dli_sname, REAL(strlen)(info->dli_sname) + 1);
1454353944Sdim  }
1455353944Sdim  return res;
1456353944Sdim}
1457353944Sdim
1458353944SdimINTERCEPTOR(char *, dlerror, int fake) {
1459353944Sdim  void *ctx;
1460353944Sdim  COMMON_INTERCEPTOR_ENTER(ctx, dlerror, fake);
1461353944Sdim  char *res = REAL(dlerror)(fake);
1462353944Sdim  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
1463353944Sdim  return res;
1464353944Sdim}
1465353944Sdim
1466353944Sdimtypedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
1467353944Sdim                                  void *data);
1468353944Sdimstruct dl_iterate_phdr_data {
1469353944Sdim  dl_iterate_phdr_cb callback;
1470353944Sdim  void *data;
1471353944Sdim};
1472353944Sdim
1473353944Sdimstatic int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
1474353944Sdim                                   void *data) {
1475353944Sdim  if (info) {
1476353944Sdim    __msan_unpoison(info, size);
1477353944Sdim    if (info->dlpi_phdr && info->dlpi_phnum)
1478353944Sdim      __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum);
1479353944Sdim    if (info->dlpi_name)
1480353944Sdim      __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
1481353944Sdim  }
1482353944Sdim  dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
1483353944Sdim  UnpoisonParam(3);
1484353944Sdim  return cbdata->callback(info, size, cbdata->data);
1485353944Sdim}
1486353944Sdim
1487353944SdimINTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
1488353944Sdim  ENSURE_MSAN_INITED();
1489353944Sdim  void *p = REAL(shmat)(shmid, shmaddr, shmflg);
1490353944Sdim  if (p != (void *)-1) {
1491353944Sdim    __sanitizer_shmid_ds ds;
1492353944Sdim    int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
1493353944Sdim    if (!res) {
1494353944Sdim      __msan_unpoison(p, ds.shm_segsz);
1495353944Sdim    }
1496353944Sdim  }
1497353944Sdim  return p;
1498353944Sdim}
1499353944Sdim
1500353944SdimINTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
1501353944Sdim  void *ctx;
1502353944Sdim  COMMON_INTERCEPTOR_ENTER(ctx, dl_iterate_phdr, callback, data);
1503353944Sdim  dl_iterate_phdr_data cbdata;
1504353944Sdim  cbdata.callback = callback;
1505353944Sdim  cbdata.data = data;
1506353944Sdim  int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
1507353944Sdim  return res;
1508353944Sdim}
1509353944Sdim
1510353944Sdim// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
1511353944SdimINTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
1512353944Sdim  ENSURE_MSAN_INITED();
1513353944Sdim  wchar_t *res = REAL(wcschr)(s, wc, ps);
1514353944Sdim  return res;
1515353944Sdim}
1516353944Sdim
1517353944Sdim// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
1518353944SdimINTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
1519353944Sdim  ENSURE_MSAN_INITED();
1520353944Sdim  GET_STORE_STACK_TRACE;
1521353944Sdim  wchar_t *res = REAL(wcscpy)(dest, src);
1522353944Sdim  CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1),
1523353944Sdim                      &stack);
1524353944Sdim  return res;
1525353944Sdim}
1526353944Sdim
1527353944SdimINTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
1528353944Sdim  ENSURE_MSAN_INITED();
1529353944Sdim  GET_STORE_STACK_TRACE;
1530353944Sdim  SIZE_T copy_size = REAL(wcsnlen)(src, n);
1531353944Sdim  if (copy_size < n) copy_size++;           // trailing \0
1532353944Sdim  wchar_t *res = REAL(wcsncpy)(dest, src, n);
1533353944Sdim  CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack);
1534353944Sdim  __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t));
1535353944Sdim  return res;
1536353944Sdim}
1537353944Sdim
1538353944Sdim// These interface functions reside here so that they can use
1539353944Sdim// REAL(memset), etc.
1540353944Sdimvoid __msan_unpoison(const void *a, uptr size) {
1541353944Sdim  if (!MEM_IS_APP(a)) return;
1542353944Sdim  SetShadow(a, size, 0);
1543353944Sdim}
1544353944Sdim
1545353944Sdimvoid __msan_poison(const void *a, uptr size) {
1546353944Sdim  if (!MEM_IS_APP(a)) return;
1547353944Sdim  SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
1548353944Sdim}
1549353944Sdim
1550353944Sdimvoid __msan_poison_stack(void *a, uptr size) {
1551353944Sdim  if (!MEM_IS_APP(a)) return;
1552353944Sdim  SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
1553353944Sdim}
1554353944Sdim
1555353944Sdimvoid __msan_unpoison_param(uptr n) { UnpoisonParam(n); }
1556353944Sdim
1557353944Sdimvoid __msan_clear_and_unpoison(void *a, uptr size) {
1558353944Sdim  REAL(memset)(a, 0, size);
1559353944Sdim  SetShadow(a, size, 0);
1560353944Sdim}
1561353944Sdim
1562353944Sdimvoid *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
1563353944Sdim  if (!msan_inited) return internal_memcpy(dest, src, n);
1564353944Sdim  if (msan_init_is_running || __msan::IsInSymbolizer())
1565353944Sdim    return REAL(memcpy)(dest, src, n);
1566353944Sdim  ENSURE_MSAN_INITED();
1567353944Sdim  GET_STORE_STACK_TRACE;
1568353944Sdim  void *res = REAL(memcpy)(dest, src, n);
1569353944Sdim  CopyShadowAndOrigin(dest, src, n, &stack);
1570353944Sdim  return res;
1571353944Sdim}
1572353944Sdim
1573353944Sdimvoid *__msan_memset(void *s, int c, SIZE_T n) {
1574353944Sdim  if (!msan_inited) return internal_memset(s, c, n);
1575353944Sdim  if (msan_init_is_running) return REAL(memset)(s, c, n);
1576353944Sdim  ENSURE_MSAN_INITED();
1577353944Sdim  void *res = REAL(memset)(s, c, n);
1578353944Sdim  __msan_unpoison(s, n);
1579353944Sdim  return res;
1580353944Sdim}
1581353944Sdim
1582353944Sdimvoid *__msan_memmove(void *dest, const void *src, SIZE_T n) {
1583353944Sdim  if (!msan_inited) return internal_memmove(dest, src, n);
1584353944Sdim  if (msan_init_is_running) return REAL(memmove)(dest, src, n);
1585353944Sdim  ENSURE_MSAN_INITED();
1586353944Sdim  GET_STORE_STACK_TRACE;
1587353944Sdim  void *res = REAL(memmove)(dest, src, n);
1588353944Sdim  MoveShadowAndOrigin(dest, src, n, &stack);
1589353944Sdim  return res;
1590353944Sdim}
1591353944Sdim
1592353944Sdimvoid __msan_unpoison_string(const char* s) {
1593353944Sdim  if (!MEM_IS_APP(s)) return;
1594353944Sdim  __msan_unpoison(s, REAL(strlen)(s) + 1);
1595353944Sdim}
1596353944Sdim
1597353944Sdimnamespace __msan {
1598353944Sdim
1599353944Sdimvoid InitializeInterceptors() {
1600353944Sdim  static int inited = 0;
1601353944Sdim  CHECK_EQ(inited, 0);
1602353944Sdim
1603353944Sdim  new(interceptor_ctx()) InterceptorContext();
1604353944Sdim
1605353944Sdim  InitializeCommonInterceptors();
1606353944Sdim  InitializeSignalInterceptors();
1607353944Sdim
1608353944Sdim  INTERCEPT_FUNCTION(posix_memalign);
1609353944Sdim  MSAN_MAYBE_INTERCEPT_MEMALIGN;
1610353944Sdim  MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
1611353944Sdim  INTERCEPT_FUNCTION(valloc);
1612353944Sdim  MSAN_MAYBE_INTERCEPT_PVALLOC;
1613353944Sdim  INTERCEPT_FUNCTION(malloc);
1614353944Sdim  INTERCEPT_FUNCTION(calloc);
1615353944Sdim  INTERCEPT_FUNCTION(realloc);
1616353944Sdim  INTERCEPT_FUNCTION(reallocarray);
1617353944Sdim  INTERCEPT_FUNCTION(free);
1618353944Sdim  MSAN_MAYBE_INTERCEPT_CFREE;
1619353944Sdim  MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
1620353944Sdim  MSAN_MAYBE_INTERCEPT_MALLINFO;
1621353944Sdim  MSAN_MAYBE_INTERCEPT_MALLOPT;
1622353944Sdim  MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
1623353944Sdim  INTERCEPT_FUNCTION(fread);
1624353944Sdim  MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
1625353944Sdim  INTERCEPT_FUNCTION(memccpy);
1626353944Sdim  MSAN_MAYBE_INTERCEPT_MEMPCPY;
1627353944Sdim  INTERCEPT_FUNCTION(bcopy);
1628353944Sdim  INTERCEPT_FUNCTION(wmemset);
1629353944Sdim  INTERCEPT_FUNCTION(wmemcpy);
1630353944Sdim  MSAN_MAYBE_INTERCEPT_WMEMPCPY;
1631353944Sdim  INTERCEPT_FUNCTION(wmemmove);
1632353944Sdim  INTERCEPT_FUNCTION(strcpy);
1633353944Sdim  MSAN_MAYBE_INTERCEPT_STPCPY;
1634353944Sdim  INTERCEPT_FUNCTION(strdup);
1635353944Sdim  MSAN_MAYBE_INTERCEPT___STRDUP;
1636353944Sdim  INTERCEPT_FUNCTION(strncpy);
1637353944Sdim  MSAN_MAYBE_INTERCEPT_GCVT;
1638353944Sdim  INTERCEPT_FUNCTION(strcat);
1639353944Sdim  INTERCEPT_FUNCTION(strncat);
1640353944Sdim  INTERCEPT_STRTO(strtod);
1641353944Sdim  INTERCEPT_STRTO(strtof);
1642353944Sdim  INTERCEPT_STRTO(strtold);
1643353944Sdim  INTERCEPT_STRTO(strtol);
1644353944Sdim  INTERCEPT_STRTO(strtoul);
1645353944Sdim  INTERCEPT_STRTO(strtoll);
1646353944Sdim  INTERCEPT_STRTO(strtoull);
1647353944Sdim  INTERCEPT_STRTO(strtouq);
1648353944Sdim  INTERCEPT_STRTO(wcstod);
1649353944Sdim  INTERCEPT_STRTO(wcstof);
1650353944Sdim  INTERCEPT_STRTO(wcstold);
1651353944Sdim  INTERCEPT_STRTO(wcstol);
1652353944Sdim  INTERCEPT_STRTO(wcstoul);
1653353944Sdim  INTERCEPT_STRTO(wcstoll);
1654353944Sdim  INTERCEPT_STRTO(wcstoull);
1655353944Sdim#ifdef SANITIZER_NLDBL_VERSION
1656353944Sdim  INTERCEPT_FUNCTION_VER(vswprintf, SANITIZER_NLDBL_VERSION);
1657353944Sdim  INTERCEPT_FUNCTION_VER(swprintf, SANITIZER_NLDBL_VERSION);
1658353944Sdim#else
1659353944Sdim  INTERCEPT_FUNCTION(vswprintf);
1660353944Sdim  INTERCEPT_FUNCTION(swprintf);
1661353944Sdim#endif
1662353944Sdim  INTERCEPT_FUNCTION(strftime);
1663353944Sdim  INTERCEPT_FUNCTION(strftime_l);
1664353944Sdim  MSAN_MAYBE_INTERCEPT___STRFTIME_L;
1665353944Sdim  INTERCEPT_FUNCTION(wcsftime);
1666353944Sdim  INTERCEPT_FUNCTION(wcsftime_l);
1667353944Sdim  MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
1668353944Sdim  INTERCEPT_FUNCTION(mbtowc);
1669353944Sdim  INTERCEPT_FUNCTION(mbrtowc);
1670353944Sdim  INTERCEPT_FUNCTION(wcslen);
1671353944Sdim  INTERCEPT_FUNCTION(wcsnlen);
1672353944Sdim  INTERCEPT_FUNCTION(wcschr);
1673353944Sdim  INTERCEPT_FUNCTION(wcscpy);
1674353944Sdim  INTERCEPT_FUNCTION(wcsncpy);
1675353944Sdim  INTERCEPT_FUNCTION(wcscmp);
1676353944Sdim  INTERCEPT_FUNCTION(getenv);
1677353944Sdim  INTERCEPT_FUNCTION(setenv);
1678353944Sdim  INTERCEPT_FUNCTION(putenv);
1679353944Sdim  INTERCEPT_FUNCTION(gettimeofday);
1680353944Sdim  MSAN_MAYBE_INTERCEPT_FCVT;
1681353944Sdim  MSAN_MAYBE_INTERCEPT_FSTAT;
1682353944Sdim  MSAN_MAYBE_INTERCEPT___FXSTAT;
1683353944Sdim  MSAN_INTERCEPT_FSTATAT;
1684353944Sdim  MSAN_MAYBE_INTERCEPT___FXSTAT64;
1685353944Sdim  MSAN_MAYBE_INTERCEPT___FXSTATAT64;
1686353944Sdim  INTERCEPT_FUNCTION(pipe);
1687353944Sdim  INTERCEPT_FUNCTION(pipe2);
1688353944Sdim  INTERCEPT_FUNCTION(socketpair);
1689353944Sdim  MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
1690353944Sdim  INTERCEPT_FUNCTION(getrlimit);
1691353944Sdim  MSAN_MAYBE_INTERCEPT___GETRLIMIT;
1692353944Sdim  MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
1693353944Sdim  MSAN_MAYBE_INTERCEPT_PRLIMIT;
1694353944Sdim  MSAN_MAYBE_INTERCEPT_PRLIMIT64;
1695353944Sdim  MSAN_INTERCEPT_UNAME;
1696353944Sdim  INTERCEPT_FUNCTION(gethostname);
1697353944Sdim  MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
1698353944Sdim  MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
1699353944Sdim  INTERCEPT_FUNCTION(dladdr);
1700353944Sdim  INTERCEPT_FUNCTION(dlerror);
1701353944Sdim  INTERCEPT_FUNCTION(dl_iterate_phdr);
1702353944Sdim  INTERCEPT_FUNCTION(getrusage);
1703353944Sdim#if defined(__mips__)
1704353944Sdim  INTERCEPT_FUNCTION_VER(pthread_create, "GLIBC_2.2");
1705353944Sdim#else
1706353944Sdim  INTERCEPT_FUNCTION(pthread_create);
1707353944Sdim#endif
1708353944Sdim  INTERCEPT_FUNCTION(pthread_key_create);
1709353944Sdim
1710353944Sdim#if SANITIZER_NETBSD
1711353944Sdim  INTERCEPT_FUNCTION(__libc_thr_keycreate);
1712353944Sdim#endif
1713353944Sdim
1714353944Sdim  INTERCEPT_FUNCTION(pthread_join);
1715353944Sdim  INTERCEPT_FUNCTION(tzset);
1716353944Sdim  INTERCEPT_FUNCTION(atexit);
1717353944Sdim  INTERCEPT_FUNCTION(__cxa_atexit);
1718353944Sdim  INTERCEPT_FUNCTION(shmat);
1719353944Sdim  INTERCEPT_FUNCTION(fork);
1720353944Sdim  MSAN_MAYBE_INTERCEPT_OPENPTY;
1721353944Sdim  MSAN_MAYBE_INTERCEPT_FORKPTY;
1722353944Sdim
1723353944Sdim  inited = 1;
1724353944Sdim}
1725353944Sdim} // namespace __msan
1726