Fix compilation of server.cc on hpux.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_posix.cpp
blobb0e32b50c0764e53cb2cc9c3bc33aa34992081e7
1 //===-- sanitizer_posix.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries and implements POSIX-specific functions from
11 // sanitizer_posix.h.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_platform.h"
16 #if SANITIZER_POSIX
18 #include "sanitizer_common.h"
19 #include "sanitizer_file.h"
20 #include "sanitizer_flags.h"
21 #include "sanitizer_libc.h"
22 #include "sanitizer_posix.h"
23 #include "sanitizer_procmaps.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <sys/mman.h>
30 #if SANITIZER_FREEBSD
31 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
32 // that, it was never implemented. So just define it to zero.
33 #undef MAP_NORESERVE
34 #define MAP_NORESERVE 0
35 #endif
37 namespace __sanitizer {
39 // ------------- sanitizer_common.h
40 uptr GetMmapGranularity() {
41 return GetPageSize();
44 bool ErrorIsOOM(error_t err) { return err == ENOMEM; }
46 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
47 size = RoundUpTo(size, GetPageSizeCached());
48 uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
49 MAP_PRIVATE | MAP_ANON, mem_type);
50 int reserrno;
51 if (UNLIKELY(internal_iserror(res, &reserrno)))
52 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
53 IncreaseTotalMmap(size);
54 return (void *)res;
57 void UnmapOrDie(void *addr, uptr size) {
58 if (!addr || !size) return;
59 uptr res = internal_munmap(addr, size);
60 if (UNLIKELY(internal_iserror(res))) {
61 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
62 SanitizerToolName, size, size, addr);
63 CHECK("unable to unmap" && 0);
65 DecreaseTotalMmap(size);
68 void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
69 size = RoundUpTo(size, GetPageSizeCached());
70 uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
71 MAP_PRIVATE | MAP_ANON, mem_type);
72 int reserrno;
73 if (UNLIKELY(internal_iserror(res, &reserrno))) {
74 if (reserrno == ENOMEM)
75 return nullptr;
76 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
78 IncreaseTotalMmap(size);
79 return (void *)res;
82 // We want to map a chunk of address space aligned to 'alignment'.
83 // We do it by mapping a bit more and then unmapping redundant pieces.
84 // We probably can do it with fewer syscalls in some OS-dependent way.
85 void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
86 const char *mem_type) {
87 CHECK(IsPowerOfTwo(size));
88 CHECK(IsPowerOfTwo(alignment));
89 uptr map_size = size + alignment;
90 uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
91 if (UNLIKELY(!map_res))
92 return nullptr;
93 uptr map_end = map_res + map_size;
94 uptr res = map_res;
95 if (!IsAligned(res, alignment)) {
96 res = (map_res + alignment - 1) & ~(alignment - 1);
97 UnmapOrDie((void*)map_res, res - map_res);
99 uptr end = res + size;
100 end = RoundUpTo(end, GetPageSizeCached());
101 if (end != map_end)
102 UnmapOrDie((void*)end, map_end - end);
103 return (void*)res;
106 void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
107 size = RoundUpTo(size, GetPageSizeCached());
108 uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
109 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type);
110 int reserrno;
111 if (UNLIKELY(internal_iserror(p, &reserrno)))
112 ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
113 IncreaseTotalMmap(size);
114 return (void *)p;
117 static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem,
118 const char *name) {
119 size = RoundUpTo(size, GetPageSizeCached());
120 fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached());
121 uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE,
122 MAP_PRIVATE | MAP_ANON | MAP_FIXED, name);
123 int reserrno;
124 if (UNLIKELY(internal_iserror(p, &reserrno))) {
125 if (tolerate_enomem && reserrno == ENOMEM)
126 return nullptr;
127 char mem_type[40];
128 internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
129 fixed_addr);
130 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
132 IncreaseTotalMmap(size);
133 return (void *)p;
136 void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
137 return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name);
140 void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
141 return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name);
144 bool MprotectNoAccess(uptr addr, uptr size) {
145 return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
148 bool MprotectReadOnly(uptr addr, uptr size) {
149 return 0 == internal_mprotect((void *)addr, size, PROT_READ);
152 #if !SANITIZER_APPLE
153 void MprotectMallocZones(void *addr, int prot) {}
154 #endif
156 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
157 if (ShouldMockFailureToOpen(filename))
158 return kInvalidFd;
159 int flags;
160 switch (mode) {
161 case RdOnly: flags = O_RDONLY; break;
162 case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
163 case RdWr: flags = O_RDWR | O_CREAT; break;
165 fd_t res = internal_open(filename, flags, 0660);
166 if (internal_iserror(res, errno_p))
167 return kInvalidFd;
168 return ReserveStandardFds(res);
171 void CloseFile(fd_t fd) {
172 internal_close(fd);
175 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
176 error_t *error_p) {
177 uptr res = internal_read(fd, buff, buff_size);
178 if (internal_iserror(res, error_p))
179 return false;
180 if (bytes_read)
181 *bytes_read = res;
182 return true;
185 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
186 error_t *error_p) {
187 uptr res = internal_write(fd, buff, buff_size);
188 if (internal_iserror(res, error_p))
189 return false;
190 if (bytes_written)
191 *bytes_written = res;
192 return true;
195 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
196 fd_t fd = OpenFile(file_name, RdOnly);
197 CHECK(fd != kInvalidFd);
198 uptr fsize = internal_filesize(fd);
199 CHECK_NE(fsize, (uptr)-1);
200 CHECK_GT(fsize, 0);
201 *buff_size = RoundUpTo(fsize, GetPageSizeCached());
202 uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
203 return internal_iserror(map) ? nullptr : (void *)map;
206 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
207 uptr flags = MAP_SHARED;
208 if (addr) flags |= MAP_FIXED;
209 uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
210 int mmap_errno = 0;
211 if (internal_iserror(p, &mmap_errno)) {
212 Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
213 fd, (long long)offset, size, p, mmap_errno);
214 return nullptr;
216 return (void *)p;
219 static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
220 uptr start2, uptr end2) {
221 CHECK(start1 <= end1);
222 CHECK(start2 <= end2);
223 return (end1 < start2) || (end2 < start1);
226 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
227 // When the shadow is mapped only a single thread usually exists (plus maybe
228 // several worker threads on Mac, which aren't expected to map big chunks of
229 // memory).
230 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
231 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
232 if (proc_maps.Error())
233 return true; // and hope for the best
234 MemoryMappedSegment segment;
235 while (proc_maps.Next(&segment)) {
236 if (segment.start == segment.end) continue; // Empty range.
237 CHECK_NE(0, segment.end);
238 if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
239 range_end))
240 return false;
242 return true;
245 #if !SANITIZER_APPLE
246 void DumpProcessMap() {
247 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
248 const sptr kBufSize = 4095;
249 char *filename = (char*)MmapOrDie(kBufSize, __func__);
250 MemoryMappedSegment segment(filename, kBufSize);
251 Report("Process memory map follows:\n");
252 while (proc_maps.Next(&segment)) {
253 Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
254 segment.filename);
256 Report("End of process memory map.\n");
257 UnmapOrDie(filename, kBufSize);
259 #endif
261 const char *GetPwd() {
262 return GetEnv("PWD");
265 bool IsPathSeparator(const char c) {
266 return c == '/';
269 bool IsAbsolutePath(const char *path) {
270 return path != nullptr && IsPathSeparator(path[0]);
273 void ReportFile::Write(const char *buffer, uptr length) {
274 SpinMutexLock l(mu);
275 ReopenIfNecessary();
276 internal_write(fd, buffer, length);
279 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
280 MemoryMappingLayout proc_maps(/*cache_enabled*/false);
281 InternalMmapVector<char> buff(kMaxPathLength);
282 MemoryMappedSegment segment(buff.data(), buff.size());
283 while (proc_maps.Next(&segment)) {
284 if (segment.IsExecutable() &&
285 internal_strcmp(module, segment.filename) == 0) {
286 *start = segment.start;
287 *end = segment.end;
288 return true;
291 return false;
294 uptr SignalContext::GetAddress() const {
295 auto si = static_cast<const siginfo_t *>(siginfo);
296 return (uptr)si->si_addr;
299 bool SignalContext::IsMemoryAccess() const {
300 auto si = static_cast<const siginfo_t *>(siginfo);
301 return si->si_signo == SIGSEGV || si->si_signo == SIGBUS;
304 int SignalContext::GetType() const {
305 return static_cast<const siginfo_t *>(siginfo)->si_signo;
308 const char *SignalContext::Describe() const {
309 switch (GetType()) {
310 case SIGFPE:
311 return "FPE";
312 case SIGILL:
313 return "ILL";
314 case SIGABRT:
315 return "ABRT";
316 case SIGSEGV:
317 return "SEGV";
318 case SIGBUS:
319 return "BUS";
320 case SIGTRAP:
321 return "TRAP";
323 return "UNKNOWN SIGNAL";
326 fd_t ReserveStandardFds(fd_t fd) {
327 CHECK_GE(fd, 0);
328 if (fd > 2)
329 return fd;
330 bool used[3];
331 internal_memset(used, 0, sizeof(used));
332 while (fd <= 2) {
333 used[fd] = true;
334 fd = internal_dup(fd);
336 for (int i = 0; i <= 2; ++i)
337 if (used[i])
338 internal_close(i);
339 return fd;
342 bool ShouldMockFailureToOpen(const char *path) {
343 return common_flags()->test_only_emulate_no_memorymap &&
344 internal_strncmp(path, "/proc/", 6) == 0;
347 #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
348 int GetNamedMappingFd(const char *name, uptr size, int *flags) {
349 if (!common_flags()->decorate_proc_maps || !name)
350 return -1;
351 char shmname[200];
352 CHECK(internal_strlen(name) < sizeof(shmname) - 10);
353 internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
354 internal_getpid(), name);
355 int o_cloexec = 0;
356 #if defined(O_CLOEXEC)
357 o_cloexec = O_CLOEXEC;
358 #endif
359 int fd = ReserveStandardFds(
360 internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
361 CHECK_GE(fd, 0);
362 int res = internal_ftruncate(fd, size);
363 #if !defined(O_CLOEXEC)
364 res = fcntl(fd, F_SETFD, FD_CLOEXEC);
365 CHECK_EQ(0, res);
366 #endif
367 CHECK_EQ(0, res);
368 res = internal_unlink(shmname);
369 CHECK_EQ(0, res);
370 *flags &= ~(MAP_ANON | MAP_ANONYMOUS);
371 return fd;
373 #else
374 int GetNamedMappingFd(const char *name, uptr size, int *flags) {
375 return -1;
377 #endif
379 #if SANITIZER_ANDROID
380 #define PR_SET_VMA 0x53564d41
381 #define PR_SET_VMA_ANON_NAME 0
382 void DecorateMapping(uptr addr, uptr size, const char *name) {
383 if (!common_flags()->decorate_proc_maps || !name)
384 return;
385 internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name);
387 #else
388 void DecorateMapping(uptr addr, uptr size, const char *name) {
390 #endif
392 uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) {
393 int fd = GetNamedMappingFd(name, length, &flags);
394 uptr res = internal_mmap(addr, length, prot, flags, fd, 0);
395 if (!internal_iserror(res))
396 DecorateMapping(res, length, name);
397 return res;
401 } // namespace __sanitizer
403 #endif // SANITIZER_POSIX