blob: b0e837a4badb6b9c10667a679baa5f34225a97cc [file] [log] [blame]
Evgeniy Stepanovc5033782012-12-11 12:27:27 +00001//===-- msan_interceptors.cc ----------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of MemorySanitizer.
11//
12// Interceptors for standard library functions.
Kostya Serebryany9a58d392012-12-12 09:54:35 +000013//
14// FIXME: move as many interceptors as possible into
15// sanitizer_common/sanitizer_common_interceptors.h
Evgeniy Stepanovc5033782012-12-11 12:27:27 +000016//===----------------------------------------------------------------------===//
17
18#include "interception/interception.h"
19#include "msan.h"
20#include "msan_platform_limits_posix.h"
21#include "sanitizer_common/sanitizer_common.h"
22#include "sanitizer_common/sanitizer_libc.h"
23
24#include <stdarg.h>
25// ACHTUNG! No other system header includes in this file.
26// Ideally, we should get rid of stdarg.h as well.
27
28typedef uptr size_t;
29typedef sptr ssize_t;
30typedef u64 off_t;
31typedef u64 off64_t;
32using namespace __msan;
33
34#define ENSURE_MSAN_INITED() do { \
35 CHECK(!msan_init_is_running); \
36 if (!msan_inited) { \
37 __msan_init(); \
38 } \
39} while (0)
40
41#define CHECK_UNPOISONED(x, n) \
42 do { \
43 sptr offset = __msan_test_shadow(x, n); \
44 if (offset >= 0 && flags()->report_umrs) { \
45 GET_CALLER_PC_BP_SP; \
46 (void)sp; \
47 Printf("UMR in %s at offset %d inside [%p, +%d) \n", \
48 __FUNCTION__, offset, x, n); \
49 __msan::PrintWarningWithOrigin( \
50 pc, bp, __msan_get_origin((char*)x + offset)); \
51 } \
52 } while (0)
53
54static void *fast_memset(void *ptr, int c, size_t n);
55static void *fast_memcpy(void *dst, const void *src, size_t n);
56
57INTERCEPTOR(size_t, fread, void *ptr, size_t size, size_t nmemb, void *file) {
58 ENSURE_MSAN_INITED();
59 size_t res = REAL(fread)(ptr, size, nmemb, file);
60 if (res > 0)
61 __msan_unpoison(ptr, res *size);
62 return res;
63}
64
65INTERCEPTOR(size_t, fread_unlocked, void *ptr, size_t size, size_t nmemb,
66 void *file) {
67 ENSURE_MSAN_INITED();
68 size_t res = REAL(fread_unlocked)(ptr, size, nmemb, file);
69 if (res > 0)
70 __msan_unpoison(ptr, res *size);
71 return res;
72}
73
74INTERCEPTOR(ssize_t, read, int fd, void *ptr, size_t count) {
75 ENSURE_MSAN_INITED();
76 ssize_t res = REAL(read)(fd, ptr, count);
77 if (res > 0)
78 __msan_unpoison(ptr, res);
79 return res;
80}
81
82INTERCEPTOR(ssize_t, pread, int fd, void *ptr, size_t count, off_t offset) {
83 ENSURE_MSAN_INITED();
84 ssize_t res = REAL(pread)(fd, ptr, count, offset);
85 if (res > 0)
86 __msan_unpoison(ptr, res);
87 return res;
88}
89
90INTERCEPTOR(ssize_t, pread64, int fd, void *ptr, size_t count, off64_t offset) {
91 ENSURE_MSAN_INITED();
92 ssize_t res = REAL(pread64)(fd, ptr, count, offset);
93 if (res > 0)
94 __msan_unpoison(ptr, res);
95 return res;
96}
97
98INTERCEPTOR(ssize_t, readlink, const char *path, char *buf, size_t bufsiz) {
99 ENSURE_MSAN_INITED();
100 ssize_t res = REAL(readlink)(path, buf, bufsiz);
101 if (res > 0)
102 __msan_unpoison(buf, res);
103 return res;
104}
105
106INTERCEPTOR(void *, readdir, void *a) {
107 ENSURE_MSAN_INITED();
108 void *res = REAL(readdir)(a);
109 __msan_unpoison(res, __msan::struct_dirent_sz);
110 return res;
111}
112
113INTERCEPTOR(void *, memcpy, void *dest, const void *src, size_t n) {
114 return __msan_memcpy(dest, src, n);
115}
116
117INTERCEPTOR(void *, memmove, void *dest, const void *src, size_t n) {
118 return __msan_memmove(dest, src, n);
119}
120
121INTERCEPTOR(void *, memset, void *s, int c, size_t n) {
122 return __msan_memset(s, c, n);
123}
124
125INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
126 GET_MALLOC_STACK_TRACE;
127 CHECK_EQ(alignment & (alignment - 1), 0);
128 *memptr = MsanReallocate(&stack, 0, size, alignment, false);
129 CHECK_NE(memptr, 0);
130 return 0;
131}
132
133INTERCEPTOR(void, free, void *ptr) {
134 ENSURE_MSAN_INITED();
135 if (ptr == 0) return;
136 MsanDeallocate(ptr);
137}
138
139INTERCEPTOR(size_t, strlen, const char *s) {
140 ENSURE_MSAN_INITED();
141 size_t res = REAL(strlen)(s);
142 CHECK_UNPOISONED(s, res + 1);
143 return res;
144}
145
146INTERCEPTOR(size_t, strnlen, const char *s, size_t n) {
147 ENSURE_MSAN_INITED();
148 size_t res = REAL(strnlen)(s, n);
149 size_t scan_size = (res == n) ? res : res + 1;
150 CHECK_UNPOISONED(s, scan_size);
151 return res;
152}
153
154// FIXME: Add stricter shadow checks in str* interceptors (ex.: strcpy should
155// check the shadow of the terminating \0 byte).
156
157INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
158 ENSURE_MSAN_INITED();
159 size_t n = REAL(strlen)(src);
160 char *res = REAL(strcpy)(dest, src); // NOLINT
161 __msan_copy_poison(dest, src, n + 1);
162 return res;
163}
164
165INTERCEPTOR(char *, strncpy, char *dest, const char *src, size_t n) { // NOLINT
166 ENSURE_MSAN_INITED();
167 size_t copy_size = REAL(strnlen)(src, n);
168 if (copy_size < n)
169 copy_size++; // trailing \0
170 char *res = REAL(strncpy)(dest, src, n); // NOLINT
171 __msan_copy_poison(dest, src, copy_size);
172 return res;
173}
174
175INTERCEPTOR(char *, strdup, char *src) {
176 ENSURE_MSAN_INITED();
177 size_t n = REAL(strlen)(src);
178 char *res = REAL(strdup)(src);
179 __msan_copy_poison(res, src, n + 1);
180 return res;
181}
182
183INTERCEPTOR(char *, gcvt, double number, size_t ndigit, char *buf) {
184 ENSURE_MSAN_INITED();
185 char *res = REAL(gcvt)(number, ndigit, buf);
186 // DynamoRio tool will take care of unpoisoning gcvt result for us.
187 if (!__msan_has_dynamic_component()) {
188 size_t n = REAL(strlen)(buf);
189 __msan_unpoison(buf, n + 1);
190 }
191 return res;
192}
193
194INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT
195 ENSURE_MSAN_INITED();
196 size_t src_size = REAL(strlen)(src);
197 size_t dest_size = REAL(strlen)(dest);
198 char *res = REAL(strcat)(dest, src); // NOLINT
199 __msan_copy_poison(dest + dest_size, src, src_size + 1);
200 return res;
201}
202
203INTERCEPTOR(char *, strncat, char *dest, const char *src, size_t n) { // NOLINT
204 ENSURE_MSAN_INITED();
205 size_t dest_size = REAL(strlen)(dest);
206 size_t copy_size = REAL(strlen)(src);
207 if (copy_size < n)
208 copy_size++; // trailing \0
209 char *res = REAL(strncat)(dest, src, n); // NOLINT
210 __msan_copy_poison(dest + dest_size, src, copy_size);
211 return res;
212}
213
214INTERCEPTOR(long, strtol, const char *nptr, char **endptr, // NOLINT
215 int base) {
216 ENSURE_MSAN_INITED();
217 long res = REAL(strtol)(nptr, endptr, base); // NOLINT
218 if (!__msan_has_dynamic_component()) {
219 __msan_unpoison(endptr, sizeof(*endptr));
220 }
221 return res;
222}
223
224INTERCEPTOR(long long, strtoll, const char *nptr, char **endptr, // NOLINT
225 int base) {
226 ENSURE_MSAN_INITED();
227 long res = REAL(strtoll)(nptr, endptr, base); //NOLINT
228 if (!__msan_has_dynamic_component()) {
229 __msan_unpoison(endptr, sizeof(*endptr));
230 }
231 return res;
232}
233
234INTERCEPTOR(unsigned long, strtoul, const char *nptr, char **endptr, // NOLINT
235 int base) {
236 ENSURE_MSAN_INITED();
237 unsigned long res = REAL(strtoul)(nptr, endptr, base); // NOLINT
238 if (!__msan_has_dynamic_component()) {
239 __msan_unpoison(endptr, sizeof(*endptr));
240 }
241 return res;
242}
243
244INTERCEPTOR(unsigned long long, strtoull, const char *nptr, // NOLINT
245 char **endptr, int base) {
246 ENSURE_MSAN_INITED();
247 unsigned long res = REAL(strtoull)(nptr, endptr, base); // NOLINT
248 if (!__msan_has_dynamic_component()) {
249 __msan_unpoison(endptr, sizeof(*endptr));
250 }
251 return res;
252}
253
254INTERCEPTOR(int, vsnprintf, char *str, uptr size,
255 const char *format, va_list ap) {
256 ENSURE_MSAN_INITED();
257 int res = REAL(vsnprintf)(str, size, format, ap);
258 if (!__msan_has_dynamic_component()) {
259 __msan_unpoison(str, res + 1);
260 }
261 return res;
262}
263
264INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
265 ENSURE_MSAN_INITED();
266 int res = REAL(vsprintf)(str, format, ap);
267 if (!__msan_has_dynamic_component()) {
268 __msan_unpoison(str, res + 1);
269 }
270 return res;
271}
272
273INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
274 ENSURE_MSAN_INITED();
275 int res = REAL(vswprintf)(str, size, format, ap);
276 if (!__msan_has_dynamic_component()) {
277 __msan_unpoison(str, 4 * (res + 1));
278 }
279 return res;
280}
281
282INTERCEPTOR(int, sprintf, char *str, const char *format, ...) { // NOLINT
283 ENSURE_MSAN_INITED();
284 va_list ap;
285 va_start(ap, format);
286 int res = vsprintf(str, format, ap); // NOLINT
287 va_end(ap);
288 return res;
289}
290
291INTERCEPTOR(int, snprintf, char *str, uptr size, const char *format, ...) {
292 ENSURE_MSAN_INITED();
293 va_list ap;
294 va_start(ap, format);
295 int res = vsnprintf(str, size, format, ap);
296 va_end(ap);
297 return res;
298}
299
300INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
301 ENSURE_MSAN_INITED();
302 va_list ap;
303 va_start(ap, format);
304 int res = vswprintf(str, size, format, ap);
305 va_end(ap);
306 return res;
307}
308
309// size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);
310INTERCEPTOR(size_t, strftime, char *s, size_t max, const char *format,
311 void *tm) {
312 ENSURE_MSAN_INITED();
313 size_t res = REAL(strftime)(s, max, format, tm);
314 if (res) __msan_unpoison(s, res + 1);
315 return res;
316}
317
318INTERCEPTOR(size_t, wcstombs, void *dest, void *src, size_t size) {
319 ENSURE_MSAN_INITED();
320 size_t res = REAL(wcstombs)(dest, src, size);
321 if (res != (size_t)-1) __msan_unpoison(dest, res + 1);
322 return res;
323}
324
325// size_t mbstowcs(wchar_t *dest, const char *src, size_t n);
326INTERCEPTOR(size_t, mbstowcs, wchar_t *dest, const char *src, size_t n) {
327 ENSURE_MSAN_INITED();
328 size_t res = REAL(mbstowcs)(dest, src, n);
329 if (res != (size_t)-1) __msan_unpoison(dest, (res + 1) * sizeof(wchar_t));
330 return res;
331}
332
333INTERCEPTOR(size_t, wcslen, const wchar_t *s) {
334 ENSURE_MSAN_INITED();
335 size_t res = REAL(wcslen)(s);
336 CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1));
337 return res;
338}
339
340// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
341INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
342 ENSURE_MSAN_INITED();
343 wchar_t *res = REAL(wcschr)(s, wc, ps);
344 return res;
345}
346
347// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
348INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
349 ENSURE_MSAN_INITED();
350 wchar_t *res = REAL(wcscpy)(dest, src);
351 __msan_copy_poison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1));
352 return res;
353}
354
355// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n);
356INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, size_t n) {
357 ENSURE_MSAN_INITED();
358 wchar_t *res = REAL(wmemcpy)(dest, src, n);
359 __msan_copy_poison(dest, src, n * sizeof(wchar_t));
360 return res;
361}
362
363INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, size_t n) {
364 CHECK(MEM_IS_APP(s));
365 ENSURE_MSAN_INITED();
366 wchar_t *res = (wchar_t *)fast_memset(s, c, n * sizeof(wchar_t));
367 __msan_unpoison(s, n * sizeof(wchar_t));
368 return res;
369}
370
371INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, size_t n) {
372 ENSURE_MSAN_INITED();
373 wchar_t *res = REAL(wmemmove)(dest, src, n);
374 __msan_move_poison(dest, src, n * sizeof(wchar_t));
375 return res;
376}
377
378INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
379 ENSURE_MSAN_INITED();
380 int res = REAL(wcscmp)(s1, s2);
381 return res;
382}
383
384INTERCEPTOR(double, wcstod, const wchar_t *nptr, wchar_t **endptr) {
385 ENSURE_MSAN_INITED();
386 double res = REAL(wcstod)(nptr, endptr);
387 __msan_unpoison(endptr, sizeof(*endptr));
388 return res;
389}
390
391// #define UNSUPPORTED(name) \
392// INTERCEPTOR(void, name, void) { \
393// Printf("MSAN: Unsupported %s\n", __FUNCTION__); \
394// Die(); \
395// }
396
397// FIXME: intercept the following functions:
398// Note, they only matter when running without a dynamic tool.
399// UNSUPPORTED(wcscoll_l)
400// UNSUPPORTED(wcsnrtombs)
401// UNSUPPORTED(wcstol)
402// UNSUPPORTED(wcstoll)
403// UNSUPPORTED(wcstold)
404// UNSUPPORTED(wcstoul)
405// UNSUPPORTED(wcstoull)
406// UNSUPPORTED(wcsxfrm_l)
407// UNSUPPORTED(wcsdup)
408// UNSUPPORTED(wcsftime)
409// UNSUPPORTED(wcsstr)
410// UNSUPPORTED(wcsrchr)
411// UNSUPPORTED(wctob)
412
413INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
414 ENSURE_MSAN_INITED();
415 int res = REAL(gettimeofday)(tv, tz);
416 if (tv)
417 __msan_unpoison(tv, 16);
418 if (tz)
419 __msan_unpoison(tz, 8);
420 return res;
421}
422
423INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
424 ENSURE_MSAN_INITED();
425 char *res = REAL(fcvt)(x, a, b, c);
426 if (!__msan_has_dynamic_component()) {
427 __msan_unpoison(b, sizeof(*b));
428 __msan_unpoison(c, sizeof(*c));
429 }
430 return res;
431}
432
433INTERCEPTOR(char *, getenv, char *name) {
434 ENSURE_MSAN_INITED();
435 char *res = REAL(getenv)(name);
436 if (!__msan_has_dynamic_component()) {
437 if (res)
438 __msan_unpoison(res, REAL(strlen)(res) + 1);
439 }
440 return res;
441}
442
443INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
444 ENSURE_MSAN_INITED();
445 int res = REAL(__fxstat)(magic, fd, buf);
446 if (!res)
447 __msan_unpoison(buf, __msan::struct_stat_sz);
448 return res;
449}
450
451INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
452 ENSURE_MSAN_INITED();
453 int res = REAL(__fxstat64)(magic, fd, buf);
454 if (!res)
455 __msan_unpoison(buf, __msan::struct_stat64_sz);
456 return res;
457}
458
459INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
460 ENSURE_MSAN_INITED();
461 int res = REAL(__xstat)(magic, path, buf);
462 if (!res)
463 __msan_unpoison(buf, __msan::struct_stat_sz);
464 return res;
465}
466
467INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
468 ENSURE_MSAN_INITED();
469 int res = REAL(__xstat64)(magic, path, buf);
470 if (!res)
471 __msan_unpoison(buf, __msan::struct_stat64_sz);
472 return res;
473}
474
475INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
476 ENSURE_MSAN_INITED();
477 int res = REAL(__lxstat)(magic, path, buf);
478 if (!res)
479 __msan_unpoison(buf, __msan::struct_stat_sz);
480 return res;
481}
482
483INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
484 ENSURE_MSAN_INITED();
485 int res = REAL(__lxstat64)(magic, path, buf);
486 if (!res)
487 __msan_unpoison(buf, __msan::struct_stat64_sz);
488 return res;
489}
490
491INTERCEPTOR(int, pipe, int pipefd[2]) {
492 if (msan_init_is_running)
493 return REAL(pipe)(pipefd);
494 ENSURE_MSAN_INITED();
495 int res = REAL(pipe)(pipefd);
496 if (!res)
497 __msan_unpoison(pipefd, sizeof(int[2]));
498 return res;
499}
500
501INTERCEPTOR(int, wait, int *status) {
502 ENSURE_MSAN_INITED();
503 int res = REAL(wait)(status);
504 if (status)
505 __msan_unpoison(status, sizeof(*status));
506 return res;
507}
508
509INTERCEPTOR(int, waitpid, int pid, int *status, int options) {
510 ENSURE_MSAN_INITED();
511 int res = REAL(waitpid)(pid, status, options);
512 if (status)
513 __msan_unpoison(status, sizeof(*status));
514 return res;
515}
516
517INTERCEPTOR(char *, fgets, char *s, int size, void *stream) {
518 ENSURE_MSAN_INITED();
519 char *res = REAL(fgets)(s, size, stream);
520 if (res)
521 __msan_unpoison(s, REAL(strlen)(s) + 1);
522 return res;
523}
524
525INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
526 ENSURE_MSAN_INITED();
527 char *res = REAL(fgets_unlocked)(s, size, stream);
528 if (res)
529 __msan_unpoison(s, REAL(strlen)(s) + 1);
530 return res;
531}
532
533INTERCEPTOR(char *, getcwd, char *buf, size_t size) {
534 ENSURE_MSAN_INITED();
535 char *res = REAL(getcwd)(buf, size);
536 if (res)
537 __msan_unpoison(buf, REAL(strlen)(buf) + 1);
538 return res;
539}
540
541INTERCEPTOR(char *, realpath, char *path, char *abspath) {
542 ENSURE_MSAN_INITED();
543 char *res = REAL(realpath)(path, abspath);
544 if (res)
545 __msan_unpoison(abspath, REAL(strlen)(abspath) + 1);
546 return res;
547}
548
549INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
550 if (msan_init_is_running)
551 return REAL(getrlimit)(resource, rlim);
552 ENSURE_MSAN_INITED();
553 int res = REAL(getrlimit)(resource, rlim);
554 if (!res)
555 __msan_unpoison(rlim, __msan::struct_rlimit_sz);
556 return res;
557}
558
559INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
560 if (msan_init_is_running)
561 return REAL(getrlimit64)(resource, rlim);
562 ENSURE_MSAN_INITED();
563 int res = REAL(getrlimit64)(resource, rlim);
564 if (!res)
565 __msan_unpoison(rlim, __msan::struct_rlimit64_sz);
566 return res;
567}
568
569INTERCEPTOR(int, statfs, const char *s, void *buf) {
570 ENSURE_MSAN_INITED();
571 int res = REAL(statfs)(s, buf);
572 if (!res)
573 __msan_unpoison(buf, __msan::struct_statfs_sz);
574 return res;
575}
576
577INTERCEPTOR(int, fstatfs, int fd, void *buf) {
578 ENSURE_MSAN_INITED();
579 int res = REAL(fstatfs)(fd, buf);
580 if (!res)
581 __msan_unpoison(buf, __msan::struct_statfs_sz);
582 return res;
583}
584
585INTERCEPTOR(int, statfs64, const char *s, void *buf) {
586 ENSURE_MSAN_INITED();
587 int res = REAL(statfs64)(s, buf);
588 if (!res)
589 __msan_unpoison(buf, __msan::struct_statfs64_sz);
590 return res;
591}
592
593INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
594 ENSURE_MSAN_INITED();
595 int res = REAL(fstatfs64)(fd, buf);
596 if (!res)
597 __msan_unpoison(buf, __msan::struct_statfs64_sz);
598 return res;
599}
600
601INTERCEPTOR(int, uname, void *utsname) {
602 ENSURE_MSAN_INITED();
603 int res = REAL(uname)(utsname);
604 if (!res) {
605 __msan_unpoison(utsname, __msan::struct_utsname_sz);
606 }
607 return res;
608}
609
610INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
611 int timeout) {
612 ENSURE_MSAN_INITED();
613 int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
614 if (res > 0) {
615 __msan_unpoison(events, __msan::struct_epoll_event_sz * res);
616 }
617 return res;
618}
619
620INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
621 int timeout, void *sigmask) {
622 ENSURE_MSAN_INITED();
623 int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
624 if (res > 0) {
625 __msan_unpoison(events, __msan::struct_epoll_event_sz * res);
626 }
627 return res;
628}
629
630INTERCEPTOR(ssize_t, recv, int fd, void *buf, size_t len, int flags) {
631 ENSURE_MSAN_INITED();
632 ssize_t res = REAL(recv)(fd, buf, len, flags);
633 if (res > 0)
634 __msan_unpoison(buf, res);
635 return res;
636}
637
638INTERCEPTOR(ssize_t, recvfrom, int fd, void *buf, size_t len, int flags,
639 void *srcaddr, void *addrlen) {
640 ENSURE_MSAN_INITED();
641 ssize_t res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
642 if (res > 0)
643 __msan_unpoison(buf, res);
644 return res;
645}
646
647INTERCEPTOR(ssize_t, recvmsg, int fd, struct msghdr *msg, int flags) {
648 ENSURE_MSAN_INITED();
649 ssize_t res = REAL(recvmsg)(fd, msg, flags);
650 if (res > 0) {
651 for (size_t i = 0; i < __msan_get_msghdr_iovlen(msg); ++i)
652 __msan_unpoison(__msan_get_msghdr_iov_iov_base(msg, i),
653 __msan_get_msghdr_iov_iov_len(msg, i));
654 }
655 return res;
656}
657
658INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
659 GET_MALLOC_STACK_TRACE;
660 if (!msan_inited) {
661 // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
662 const size_t kCallocPoolSize = 1024;
663 static uptr calloc_memory_for_dlsym[kCallocPoolSize];
664 static size_t allocated;
665 size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
666 void *mem = (void*)&calloc_memory_for_dlsym[allocated];
667 allocated += size_in_words;
668 CHECK(allocated < kCallocPoolSize);
669 return mem;
670 }
671 return MsanReallocate(&stack, 0, nmemb * size, sizeof(u64), true);
672}
673
674INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
675 GET_MALLOC_STACK_TRACE;
676 return MsanReallocate(&stack, ptr, size, sizeof(u64), false);
677}
678
679INTERCEPTOR(void *, malloc, size_t size) {
680 GET_MALLOC_STACK_TRACE;
681 return MsanReallocate(&stack, 0, size, sizeof(u64), false);
682}
683
684INTERCEPTOR(void *, mmap, void *addr, size_t length, int prot, int flags,
685 int fd, off_t offset) {
686 ENSURE_MSAN_INITED();
687 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
688 if (res != (void*)-1)
689 __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
690 return res;
691}
692
693INTERCEPTOR(void *, mmap64, void *addr, size_t length, int prot, int flags,
694 int fd, off64_t offset) {
695 ENSURE_MSAN_INITED();
696 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
697 if (res != (void*)-1)
698 __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
699 return res;
700}
701
702// static
703void *fast_memset(void *ptr, int c, size_t n) {
704 // hack until we have a really fast internal_memset
705 if (sizeof(uptr) == 8 &&
706 (n % 8) == 0 &&
707 ((uptr)ptr % 8) == 0 &&
708 (c == 0 || c == -1)) {
709 // Printf("memset %p %zd %x\n", ptr, n, c);
710 uptr to_store = c ? -1L : 0L;
711 uptr *p = (uptr*)ptr;
712 for (size_t i = 0; i < n / 8; i++)
713 p[i] = to_store;
714 return ptr;
715 }
716 return internal_memset(ptr, c, n);
717}
718
719// static
720void *fast_memcpy(void *dst, const void *src, size_t n) {
721 // Same hack as in fast_memset above.
722 if (sizeof(uptr) == 8 &&
723 (n % 8) == 0 &&
724 ((uptr)dst % 8) == 0 &&
725 ((uptr)src % 8) == 0) {
726 uptr *d = (uptr*)dst;
727 uptr *s = (uptr*)src;
728 for (size_t i = 0; i < n / 8; i++)
729 d[i] = s[i];
730 return dst;
731 }
732 return internal_memcpy(dst, src, n);
733}
734
735// These interface functions reside here so that they can use
736// fast_memset, etc.
737void __msan_unpoison(void *a, uptr size) {
738 if (!MEM_IS_APP(a)) return;
739 fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
740}
741
742void __msan_poison(void *a, uptr size) {
743 if (!MEM_IS_APP(a)) return;
744 fast_memset((void*)MEM_TO_SHADOW((uptr)a),
745 __msan::flags()->poison_heap_with_zeroes ? 0 : -1, size);
746}
747
748void __msan_poison_stack(void *a, uptr size) {
749 if (!MEM_IS_APP(a)) return;
750 fast_memset((void*)MEM_TO_SHADOW((uptr)a),
751 __msan::flags()->poison_stack_with_zeroes ? 0 : -1, size);
752}
753
754void __msan_clear_and_unpoison(void *a, uptr size) {
755 fast_memset(a, 0, size);
756 fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
757}
758
759void __msan_copy_origin(void *dst, const void *src, uptr size) {
760 if (!__msan_get_track_origins()) return;
761 if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
762 uptr d = MEM_TO_ORIGIN(dst);
763 uptr s = MEM_TO_ORIGIN(src);
764 uptr beg = d & ~3UL; // align down.
765 uptr end = (d + size + 3) & ~3UL; // align up.
766 s = s & ~3UL; // align down.
767 fast_memcpy((void*)beg, (void*)s, end - beg);
768}
769
770void __msan_copy_poison(void *dst, const void *src, uptr size) {
771 if (!MEM_IS_APP(dst)) return;
772 if (!MEM_IS_APP(src)) return;
773 fast_memcpy((void*)MEM_TO_SHADOW((uptr)dst),
774 (void*)MEM_TO_SHADOW((uptr)src), size);
775 __msan_copy_origin(dst, src, size);
776}
777
778void __msan_move_poison(void *dst, const void *src, uptr size) {
779 if (!MEM_IS_APP(dst)) return;
780 if (!MEM_IS_APP(src)) return;
781 internal_memmove((void*)MEM_TO_SHADOW((uptr)dst),
782 (void*)MEM_TO_SHADOW((uptr)src), size);
783 __msan_copy_origin(dst, src, size);
784}
785
786void *__msan_memcpy(void *dest, const void *src, size_t n) {
787 ENSURE_MSAN_INITED();
788 void *res = fast_memcpy(dest, src, n);
789 __msan_copy_poison(dest, src, n);
790 return res;
791}
792
793void *__msan_memset(void *s, int c, size_t n) {
794 ENSURE_MSAN_INITED();
795 void *res = fast_memset(s, c, n);
796 __msan_unpoison(s, n);
797 return res;
798}
799
800void *__msan_memmove(void *dest, const void *src, size_t n) {
801 ENSURE_MSAN_INITED();
802 void *res = REAL(memmove)(dest, src, n);
803 __msan_move_poison(dest, src, n);
804 return res;
805}
806
807namespace __msan {
808void InitializeInterceptors() {
809 static int inited = 0;
810 CHECK_EQ(inited, 0);
811 CHECK(INTERCEPT_FUNCTION(mmap));
812 CHECK(INTERCEPT_FUNCTION(mmap64));
813 CHECK(INTERCEPT_FUNCTION(posix_memalign));
814 CHECK(INTERCEPT_FUNCTION(malloc));
815 CHECK(INTERCEPT_FUNCTION(calloc));
816 CHECK(INTERCEPT_FUNCTION(realloc));
817 CHECK(INTERCEPT_FUNCTION(free));
818 CHECK(INTERCEPT_FUNCTION(fread));
819 CHECK(INTERCEPT_FUNCTION(fread_unlocked));
820 CHECK(INTERCEPT_FUNCTION(read));
821 CHECK(INTERCEPT_FUNCTION(pread));
822 CHECK(INTERCEPT_FUNCTION(pread64));
823 CHECK(INTERCEPT_FUNCTION(readlink));
824 CHECK(INTERCEPT_FUNCTION(readdir));
825 CHECK(INTERCEPT_FUNCTION(memcpy));
826 CHECK(INTERCEPT_FUNCTION(memset));
827 CHECK(INTERCEPT_FUNCTION(memmove));
828 CHECK(INTERCEPT_FUNCTION(wmemset));
829 CHECK(INTERCEPT_FUNCTION(wmemcpy));
830 CHECK(INTERCEPT_FUNCTION(wmemmove));
831 CHECK(INTERCEPT_FUNCTION(strcpy)); // NOLINT
832 CHECK(INTERCEPT_FUNCTION(strdup));
833 CHECK(INTERCEPT_FUNCTION(strncpy)); // NOLINT
834 CHECK(INTERCEPT_FUNCTION(strlen));
835 CHECK(INTERCEPT_FUNCTION(strnlen));
836 CHECK(INTERCEPT_FUNCTION(gcvt));
837 CHECK(INTERCEPT_FUNCTION(strcat)); // NOLINT
838 CHECK(INTERCEPT_FUNCTION(strncat)); // NOLINT
839 CHECK(INTERCEPT_FUNCTION(strtol));
840 CHECK(INTERCEPT_FUNCTION(strtoll));
841 CHECK(INTERCEPT_FUNCTION(strtoul));
842 CHECK(INTERCEPT_FUNCTION(strtoull));
843 CHECK(INTERCEPT_FUNCTION(vsprintf));
844 CHECK(INTERCEPT_FUNCTION(vsnprintf));
845 CHECK(INTERCEPT_FUNCTION(vswprintf));
846 CHECK(INTERCEPT_FUNCTION(sprintf)); // NOLINT
847 CHECK(INTERCEPT_FUNCTION(snprintf));
848 CHECK(INTERCEPT_FUNCTION(swprintf));
849 CHECK(INTERCEPT_FUNCTION(strftime));
850 CHECK(INTERCEPT_FUNCTION(wcstombs));
851 CHECK(INTERCEPT_FUNCTION(mbstowcs));
852 CHECK(INTERCEPT_FUNCTION(wcslen));
853 CHECK(INTERCEPT_FUNCTION(wcschr));
854 CHECK(INTERCEPT_FUNCTION(wcscpy));
855 CHECK(INTERCEPT_FUNCTION(wcscmp));
856 CHECK(INTERCEPT_FUNCTION(wcstod));
857 CHECK(INTERCEPT_FUNCTION(getenv));
858 CHECK(INTERCEPT_FUNCTION(gettimeofday));
859 CHECK(INTERCEPT_FUNCTION(fcvt));
860 CHECK(INTERCEPT_FUNCTION(__fxstat));
861 CHECK(INTERCEPT_FUNCTION(__xstat));
862 CHECK(INTERCEPT_FUNCTION(__lxstat));
863 CHECK(INTERCEPT_FUNCTION(__fxstat64));
864 CHECK(INTERCEPT_FUNCTION(__xstat64));
865 CHECK(INTERCEPT_FUNCTION(__lxstat64));
866 CHECK(INTERCEPT_FUNCTION(pipe));
867 CHECK(INTERCEPT_FUNCTION(wait));
868 CHECK(INTERCEPT_FUNCTION(waitpid));
869 CHECK(INTERCEPT_FUNCTION(fgets));
870 CHECK(INTERCEPT_FUNCTION(fgets_unlocked));
871 CHECK(INTERCEPT_FUNCTION(getcwd));
872 CHECK(INTERCEPT_FUNCTION(realpath));
873 CHECK(INTERCEPT_FUNCTION(getrlimit));
874 CHECK(INTERCEPT_FUNCTION(getrlimit64));
875 CHECK(INTERCEPT_FUNCTION(statfs));
876 CHECK(INTERCEPT_FUNCTION(fstatfs));
877 CHECK(INTERCEPT_FUNCTION(statfs64));
878 CHECK(INTERCEPT_FUNCTION(fstatfs64));
879 CHECK(INTERCEPT_FUNCTION(uname));
880 CHECK(INTERCEPT_FUNCTION(epoll_wait));
881 CHECK(INTERCEPT_FUNCTION(epoll_pwait));
882 CHECK(INTERCEPT_FUNCTION(recv));
883 CHECK(INTERCEPT_FUNCTION(recvfrom));
884 CHECK(INTERCEPT_FUNCTION(recvmsg));
885 inited = 1;
886}
887} // namespace __msan