sanitizer_posix.cc revision 9ae2883d88dd28b9c5dc862107e6e6d12a35926e
1//===-- sanitizer_posix.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 shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements POSIX-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_platform.h"
16#if SANITIZER_LINUX || SANITIZER_MAC
17
18#include "sanitizer_common.h"
19#include "sanitizer_libc.h"
20#include "sanitizer_procmaps.h"
21
22#include <errno.h>
23#include <pthread.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/mman.h>
29#include <sys/resource.h>
30#include <sys/time.h>
31#include <sys/types.h>
32#include <unistd.h>
33
34namespace __sanitizer {
35
36// ------------- sanitizer_common.h
37uptr GetPageSize() {
38  return sysconf(_SC_PAGESIZE);
39}
40
41uptr GetMmapGranularity() {
42  return GetPageSize();
43}
44
45int GetPid() {
46  return getpid();
47}
48
49u32 GetUid() {
50  return getuid();
51}
52
53uptr GetThreadSelf() {
54  return (uptr)pthread_self();
55}
56
57void *MmapOrDie(uptr size, const char *mem_type) {
58  size = RoundUpTo(size, GetPageSizeCached());
59  void *res = internal_mmap(0, size,
60                            PROT_READ | PROT_WRITE,
61                            MAP_PRIVATE | MAP_ANON, -1, 0);
62  if (res == (void*)-1) {
63    static int recursion_count;
64    if (recursion_count) {
65      // The Report() and CHECK calls below may call mmap recursively and fail.
66      // If we went into recursion, just die.
67      RawWrite("ERROR: Failed to mmap\n");
68      Die();
69    }
70    recursion_count++;
71    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
72           SanitizerToolName, size, size, mem_type, errno);
73    DumpProcessMap();
74    CHECK("unable to mmap" && 0);
75  }
76  return res;
77}
78
79void UnmapOrDie(void *addr, uptr size) {
80  if (!addr || !size) return;
81  int res = internal_munmap(addr, size);
82  if (res != 0) {
83    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
84           SanitizerToolName, size, size, addr);
85    CHECK("unable to unmap" && 0);
86  }
87}
88
89void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
90  uptr PageSize = GetPageSizeCached();
91  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
92      RoundUpTo(size, PageSize),
93      PROT_READ | PROT_WRITE,
94      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
95      -1, 0);
96  if (p == (void*)-1)
97    Report("ERROR: "
98           "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
99           SanitizerToolName, size, size, fixed_addr, errno);
100  return p;
101}
102
103void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
104  uptr PageSize = GetPageSizeCached();
105  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
106      RoundUpTo(size, PageSize),
107      PROT_READ | PROT_WRITE,
108      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
109      -1, 0);
110  if (p == (void*)-1) {
111    Report("ERROR:"
112           " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
113           SanitizerToolName, size, size, fixed_addr, errno);
114    CHECK("unable to mmap" && 0);
115  }
116  return p;
117}
118
119void *Mprotect(uptr fixed_addr, uptr size) {
120  return internal_mmap((void*)fixed_addr, size,
121                       PROT_NONE,
122                       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
123                       -1, 0);
124}
125
126void FlushUnneededShadowMemory(uptr addr, uptr size) {
127  madvise((void*)addr, size, MADV_DONTNEED);
128}
129
130void *MapFileToMemory(const char *file_name, uptr *buff_size) {
131  fd_t fd = OpenFile(file_name, false);
132  CHECK_NE(fd, kInvalidFd);
133  uptr fsize = internal_filesize(fd);
134  CHECK_NE(fsize, (uptr)-1);
135  CHECK_GT(fsize, 0);
136  *buff_size = RoundUpTo(fsize, GetPageSizeCached());
137  void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
138  return (map == MAP_FAILED) ? 0 : map;
139}
140
141
142static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
143                                        uptr start2, uptr end2) {
144  CHECK(start1 <= end1);
145  CHECK(start2 <= end2);
146  return (end1 < start2) || (end2 < start1);
147}
148
149// FIXME: this is thread-unsafe, but should not cause problems most of the time.
150// When the shadow is mapped only a single thread usually exists (plus maybe
151// several worker threads on Mac, which aren't expected to map big chunks of
152// memory).
153bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
154  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
155  uptr start, end;
156  while (proc_maps.Next(&start, &end,
157                        /*offset*/0, /*filename*/0, /*filename_size*/0,
158                        /*protection*/0)) {
159    if (!IntervalsAreSeparate(start, end, range_start, range_end))
160      return false;
161  }
162  return true;
163}
164
165void DumpProcessMap() {
166  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
167  uptr start, end;
168  const sptr kBufSize = 4095;
169  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
170  Report("Process memory map follows:\n");
171  while (proc_maps.Next(&start, &end, /* file_offset */0,
172                        filename, kBufSize, /* protection */0)) {
173    Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
174  }
175  Report("End of process memory map.\n");
176  UnmapOrDie(filename, kBufSize);
177}
178
179const char *GetPwd() {
180  return GetEnv("PWD");
181}
182
183void DisableCoreDumper() {
184  struct rlimit nocore;
185  nocore.rlim_cur = 0;
186  nocore.rlim_max = 0;
187  setrlimit(RLIMIT_CORE, &nocore);
188}
189
190bool StackSizeIsUnlimited() {
191  struct rlimit rlim;
192  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
193  return (rlim.rlim_cur == (uptr)-1);
194}
195
196void SetStackSizeLimitInBytes(uptr limit) {
197  struct rlimit rlim;
198  rlim.rlim_cur = limit;
199  rlim.rlim_max = limit;
200  if (setrlimit(RLIMIT_STACK, &rlim)) {
201    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
202    Die();
203  }
204  CHECK(!StackSizeIsUnlimited());
205}
206
207void SleepForSeconds(int seconds) {
208  sleep(seconds);
209}
210
211void SleepForMillis(int millis) {
212  usleep(millis * 1000);
213}
214
215void Abort() {
216  abort();
217}
218
219int Atexit(void (*function)(void)) {
220#ifndef SANITIZER_GO
221  return atexit(function);
222#else
223  return 0;
224#endif
225}
226
227int internal_isatty(fd_t fd) {
228  return isatty(fd);
229}
230
231}  // namespace __sanitizer
232
233#endif  // __linux__ || __APPLE_
234