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