xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- sanitizer_posix.cpp -----------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer
1068d75effSDimitry Andric // run-time libraries and implements POSIX-specific functions from
1168d75effSDimitry Andric // sanitizer_posix.h.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_platform.h"
1568d75effSDimitry Andric 
1668d75effSDimitry Andric #if SANITIZER_POSIX
1768d75effSDimitry Andric 
1868d75effSDimitry Andric #include "sanitizer_common.h"
1968d75effSDimitry Andric #include "sanitizer_file.h"
2068d75effSDimitry Andric #include "sanitizer_flags.h"
2168d75effSDimitry Andric #include "sanitizer_libc.h"
2268d75effSDimitry Andric #include "sanitizer_posix.h"
2368d75effSDimitry Andric #include "sanitizer_procmaps.h"
2468d75effSDimitry Andric 
2568d75effSDimitry Andric #include <errno.h>
2668d75effSDimitry Andric #include <fcntl.h>
2768d75effSDimitry Andric #include <signal.h>
2868d75effSDimitry Andric #include <sys/mman.h>
2968d75effSDimitry Andric 
3068d75effSDimitry Andric #if SANITIZER_FREEBSD
3168d75effSDimitry Andric // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
3268d75effSDimitry Andric // that, it was never implemented.  So just define it to zero.
3368d75effSDimitry Andric #undef  MAP_NORESERVE
3468d75effSDimitry Andric #define MAP_NORESERVE 0
3568d75effSDimitry Andric #endif
3668d75effSDimitry Andric 
3768d75effSDimitry Andric namespace __sanitizer {
3868d75effSDimitry Andric 
3968d75effSDimitry Andric // ------------- sanitizer_common.h
4068d75effSDimitry Andric uptr GetMmapGranularity() {
4168d75effSDimitry Andric   return GetPageSize();
4268d75effSDimitry Andric }
4368d75effSDimitry Andric 
4481ad6265SDimitry Andric bool ErrorIsOOM(error_t err) { return err == ENOMEM; }
4581ad6265SDimitry Andric 
4668d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
4768d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
4868d75effSDimitry Andric   uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
4968d75effSDimitry Andric                        MAP_PRIVATE | MAP_ANON, mem_type);
5068d75effSDimitry Andric   int reserrno;
5168d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno)))
5268d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
5368d75effSDimitry Andric   IncreaseTotalMmap(size);
5468d75effSDimitry Andric   return (void *)res;
5568d75effSDimitry Andric }
5668d75effSDimitry Andric 
57*0fca6ea1SDimitry Andric void UnmapOrDie(void *addr, uptr size, bool raw_report) {
5868d75effSDimitry Andric   if (!addr || !size) return;
5968d75effSDimitry Andric   uptr res = internal_munmap(addr, size);
6006c3fb27SDimitry Andric   int reserrno;
6106c3fb27SDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno)))
62*0fca6ea1SDimitry Andric     ReportMunmapFailureAndDie(addr, size, reserrno, raw_report);
6368d75effSDimitry Andric   DecreaseTotalMmap(size);
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
6668d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
6768d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
6868d75effSDimitry Andric   uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
6968d75effSDimitry Andric                        MAP_PRIVATE | MAP_ANON, mem_type);
7068d75effSDimitry Andric   int reserrno;
7168d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno))) {
7268d75effSDimitry Andric     if (reserrno == ENOMEM)
7368d75effSDimitry Andric       return nullptr;
7468d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
7568d75effSDimitry Andric   }
7668d75effSDimitry Andric   IncreaseTotalMmap(size);
7768d75effSDimitry Andric   return (void *)res;
7868d75effSDimitry Andric }
7968d75effSDimitry Andric 
8068d75effSDimitry Andric // We want to map a chunk of address space aligned to 'alignment'.
8168d75effSDimitry Andric // We do it by mapping a bit more and then unmapping redundant pieces.
8268d75effSDimitry Andric // We probably can do it with fewer syscalls in some OS-dependent way.
8368d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
8468d75effSDimitry Andric                                    const char *mem_type) {
8568d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
8668d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
8768d75effSDimitry Andric   uptr map_size = size + alignment;
88bdd1243dSDimitry Andric   // mmap maps entire pages and rounds up map_size needs to be a an integral
89bdd1243dSDimitry Andric   // number of pages.
90bdd1243dSDimitry Andric   // We need to be aware of this size for calculating end and for unmapping
91bdd1243dSDimitry Andric   // fragments before and after the alignment region.
92bdd1243dSDimitry Andric   map_size = RoundUpTo(map_size, GetPageSizeCached());
9368d75effSDimitry Andric   uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
9468d75effSDimitry Andric   if (UNLIKELY(!map_res))
9568d75effSDimitry Andric     return nullptr;
9668d75effSDimitry Andric   uptr res = map_res;
9768d75effSDimitry Andric   if (!IsAligned(res, alignment)) {
9868d75effSDimitry Andric     res = (map_res + alignment - 1) & ~(alignment - 1);
9968d75effSDimitry Andric     UnmapOrDie((void*)map_res, res - map_res);
10068d75effSDimitry Andric   }
101bdd1243dSDimitry Andric   uptr map_end = map_res + map_size;
10268d75effSDimitry Andric   uptr end = res + size;
10381ad6265SDimitry Andric   end = RoundUpTo(end, GetPageSizeCached());
104bdd1243dSDimitry Andric   if (end != map_end) {
105bdd1243dSDimitry Andric     CHECK_LT(end, map_end);
10668d75effSDimitry Andric     UnmapOrDie((void*)end, map_end - end);
107bdd1243dSDimitry Andric   }
10868d75effSDimitry Andric   return (void*)res;
10968d75effSDimitry Andric }
11068d75effSDimitry Andric 
11168d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
11268d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
11368d75effSDimitry Andric   uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
11468d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type);
11568d75effSDimitry Andric   int reserrno;
11668d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno)))
11768d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
11868d75effSDimitry Andric   IncreaseTotalMmap(size);
11968d75effSDimitry Andric   return (void *)p;
12068d75effSDimitry Andric }
12168d75effSDimitry Andric 
12268d75effSDimitry Andric static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem,
12368d75effSDimitry Andric                            const char *name) {
12468d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
12568d75effSDimitry Andric   fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached());
12668d75effSDimitry Andric   uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE,
12768d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_FIXED, name);
12868d75effSDimitry Andric   int reserrno;
12968d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno))) {
13068d75effSDimitry Andric     if (tolerate_enomem && reserrno == ENOMEM)
13168d75effSDimitry Andric       return nullptr;
13268d75effSDimitry Andric     char mem_type[40];
133*0fca6ea1SDimitry Andric     internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p",
134*0fca6ea1SDimitry Andric                       (void *)fixed_addr);
13568d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
13668d75effSDimitry Andric   }
13768d75effSDimitry Andric   IncreaseTotalMmap(size);
13868d75effSDimitry Andric   return (void *)p;
13968d75effSDimitry Andric }
14068d75effSDimitry Andric 
14168d75effSDimitry Andric void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
14268d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name);
14368d75effSDimitry Andric }
14468d75effSDimitry Andric 
14568d75effSDimitry Andric void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
14668d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name);
14768d75effSDimitry Andric }
14868d75effSDimitry Andric 
14968d75effSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
15068d75effSDimitry Andric   return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
15168d75effSDimitry Andric }
15268d75effSDimitry Andric 
15368d75effSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
15468d75effSDimitry Andric   return 0 == internal_mprotect((void *)addr, size, PROT_READ);
15568d75effSDimitry Andric }
15668d75effSDimitry Andric 
15706c3fb27SDimitry Andric bool MprotectReadWrite(uptr addr, uptr size) {
15806c3fb27SDimitry Andric   return 0 == internal_mprotect((void *)addr, size, PROT_READ | PROT_WRITE);
15906c3fb27SDimitry Andric }
16006c3fb27SDimitry Andric 
16181ad6265SDimitry Andric #if !SANITIZER_APPLE
16268d75effSDimitry Andric void MprotectMallocZones(void *addr, int prot) {}
16368d75effSDimitry Andric #endif
16468d75effSDimitry Andric 
16568d75effSDimitry Andric fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
16668d75effSDimitry Andric   if (ShouldMockFailureToOpen(filename))
16768d75effSDimitry Andric     return kInvalidFd;
16868d75effSDimitry Andric   int flags;
16968d75effSDimitry Andric   switch (mode) {
17068d75effSDimitry Andric     case RdOnly: flags = O_RDONLY; break;
17168d75effSDimitry Andric     case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
17268d75effSDimitry Andric     case RdWr: flags = O_RDWR | O_CREAT; break;
17368d75effSDimitry Andric   }
17468d75effSDimitry Andric   fd_t res = internal_open(filename, flags, 0660);
17568d75effSDimitry Andric   if (internal_iserror(res, errno_p))
17668d75effSDimitry Andric     return kInvalidFd;
17768d75effSDimitry Andric   return ReserveStandardFds(res);
17868d75effSDimitry Andric }
17968d75effSDimitry Andric 
18068d75effSDimitry Andric void CloseFile(fd_t fd) {
18168d75effSDimitry Andric   internal_close(fd);
18268d75effSDimitry Andric }
18368d75effSDimitry Andric 
18468d75effSDimitry Andric bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
18568d75effSDimitry Andric                   error_t *error_p) {
18668d75effSDimitry Andric   uptr res = internal_read(fd, buff, buff_size);
18768d75effSDimitry Andric   if (internal_iserror(res, error_p))
18868d75effSDimitry Andric     return false;
18968d75effSDimitry Andric   if (bytes_read)
19068d75effSDimitry Andric     *bytes_read = res;
19168d75effSDimitry Andric   return true;
19268d75effSDimitry Andric }
19368d75effSDimitry Andric 
19468d75effSDimitry Andric bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
19568d75effSDimitry Andric                  error_t *error_p) {
19668d75effSDimitry Andric   uptr res = internal_write(fd, buff, buff_size);
19768d75effSDimitry Andric   if (internal_iserror(res, error_p))
19868d75effSDimitry Andric     return false;
19968d75effSDimitry Andric   if (bytes_written)
20068d75effSDimitry Andric     *bytes_written = res;
20168d75effSDimitry Andric   return true;
20268d75effSDimitry Andric }
20368d75effSDimitry Andric 
20468d75effSDimitry Andric void *MapFileToMemory(const char *file_name, uptr *buff_size) {
20568d75effSDimitry Andric   fd_t fd = OpenFile(file_name, RdOnly);
20668d75effSDimitry Andric   CHECK(fd != kInvalidFd);
20768d75effSDimitry Andric   uptr fsize = internal_filesize(fd);
20868d75effSDimitry Andric   CHECK_NE(fsize, (uptr)-1);
20968d75effSDimitry Andric   CHECK_GT(fsize, 0);
21068d75effSDimitry Andric   *buff_size = RoundUpTo(fsize, GetPageSizeCached());
21168d75effSDimitry Andric   uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
21268d75effSDimitry Andric   return internal_iserror(map) ? nullptr : (void *)map;
21368d75effSDimitry Andric }
21468d75effSDimitry Andric 
21568d75effSDimitry Andric void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
21668d75effSDimitry Andric   uptr flags = MAP_SHARED;
21768d75effSDimitry Andric   if (addr) flags |= MAP_FIXED;
21868d75effSDimitry Andric   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
21968d75effSDimitry Andric   int mmap_errno = 0;
22068d75effSDimitry Andric   if (internal_iserror(p, &mmap_errno)) {
22168d75effSDimitry Andric     Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
22268d75effSDimitry Andric            fd, (long long)offset, size, p, mmap_errno);
22368d75effSDimitry Andric     return nullptr;
22468d75effSDimitry Andric   }
22568d75effSDimitry Andric   return (void *)p;
22668d75effSDimitry Andric }
22768d75effSDimitry Andric 
22868d75effSDimitry Andric static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
22968d75effSDimitry Andric                                         uptr start2, uptr end2) {
23068d75effSDimitry Andric   CHECK(start1 <= end1);
23168d75effSDimitry Andric   CHECK(start2 <= end2);
23268d75effSDimitry Andric   return (end1 < start2) || (end2 < start1);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric 
23568d75effSDimitry Andric // FIXME: this is thread-unsafe, but should not cause problems most of the time.
23668d75effSDimitry Andric // When the shadow is mapped only a single thread usually exists (plus maybe
23768d75effSDimitry Andric // several worker threads on Mac, which aren't expected to map big chunks of
23868d75effSDimitry Andric // memory).
23968d75effSDimitry Andric bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
24068d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
24168d75effSDimitry Andric   if (proc_maps.Error())
24268d75effSDimitry Andric     return true; // and hope for the best
24368d75effSDimitry Andric   MemoryMappedSegment segment;
24468d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
24568d75effSDimitry Andric     if (segment.start == segment.end) continue;  // Empty range.
24668d75effSDimitry Andric     CHECK_NE(0, segment.end);
24768d75effSDimitry Andric     if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
24868d75effSDimitry Andric                               range_end))
24968d75effSDimitry Andric       return false;
25068d75effSDimitry Andric   }
25168d75effSDimitry Andric   return true;
25268d75effSDimitry Andric }
25368d75effSDimitry Andric 
25481ad6265SDimitry Andric #if !SANITIZER_APPLE
25568d75effSDimitry Andric void DumpProcessMap() {
25668d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
25768d75effSDimitry Andric   const sptr kBufSize = 4095;
25868d75effSDimitry Andric   char *filename = (char*)MmapOrDie(kBufSize, __func__);
25968d75effSDimitry Andric   MemoryMappedSegment segment(filename, kBufSize);
26068d75effSDimitry Andric   Report("Process memory map follows:\n");
26168d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
26268d75effSDimitry Andric     Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
26368d75effSDimitry Andric            segment.filename);
26468d75effSDimitry Andric   }
26568d75effSDimitry Andric   Report("End of process memory map.\n");
26668d75effSDimitry Andric   UnmapOrDie(filename, kBufSize);
26768d75effSDimitry Andric }
268e8d8bef9SDimitry Andric #endif
26968d75effSDimitry Andric 
27068d75effSDimitry Andric const char *GetPwd() {
27168d75effSDimitry Andric   return GetEnv("PWD");
27268d75effSDimitry Andric }
27368d75effSDimitry Andric 
27468d75effSDimitry Andric bool IsPathSeparator(const char c) {
27568d75effSDimitry Andric   return c == '/';
27668d75effSDimitry Andric }
27768d75effSDimitry Andric 
27868d75effSDimitry Andric bool IsAbsolutePath(const char *path) {
27968d75effSDimitry Andric   return path != nullptr && IsPathSeparator(path[0]);
28068d75effSDimitry Andric }
28168d75effSDimitry Andric 
28268d75effSDimitry Andric void ReportFile::Write(const char *buffer, uptr length) {
28368d75effSDimitry Andric   SpinMutexLock l(mu);
28468d75effSDimitry Andric   ReopenIfNecessary();
28568d75effSDimitry Andric   internal_write(fd, buffer, length);
28668d75effSDimitry Andric }
28768d75effSDimitry Andric 
28868d75effSDimitry Andric bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
28968d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
290fe6060f1SDimitry Andric   InternalMmapVector<char> buff(kMaxPathLength);
291fe6060f1SDimitry Andric   MemoryMappedSegment segment(buff.data(), buff.size());
29268d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
29368d75effSDimitry Andric     if (segment.IsExecutable() &&
29468d75effSDimitry Andric         internal_strcmp(module, segment.filename) == 0) {
29568d75effSDimitry Andric       *start = segment.start;
29668d75effSDimitry Andric       *end = segment.end;
29768d75effSDimitry Andric       return true;
29868d75effSDimitry Andric     }
29968d75effSDimitry Andric   }
30068d75effSDimitry Andric   return false;
30168d75effSDimitry Andric }
30268d75effSDimitry Andric 
30368d75effSDimitry Andric uptr SignalContext::GetAddress() const {
30468d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
30568d75effSDimitry Andric   return (uptr)si->si_addr;
30668d75effSDimitry Andric }
30768d75effSDimitry Andric 
30868d75effSDimitry Andric bool SignalContext::IsMemoryAccess() const {
30968d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
310e8d8bef9SDimitry Andric   return si->si_signo == SIGSEGV || si->si_signo == SIGBUS;
31168d75effSDimitry Andric }
31268d75effSDimitry Andric 
31368d75effSDimitry Andric int SignalContext::GetType() const {
31468d75effSDimitry Andric   return static_cast<const siginfo_t *>(siginfo)->si_signo;
31568d75effSDimitry Andric }
31668d75effSDimitry Andric 
31768d75effSDimitry Andric const char *SignalContext::Describe() const {
31868d75effSDimitry Andric   switch (GetType()) {
31968d75effSDimitry Andric     case SIGFPE:
32068d75effSDimitry Andric       return "FPE";
32168d75effSDimitry Andric     case SIGILL:
32268d75effSDimitry Andric       return "ILL";
32368d75effSDimitry Andric     case SIGABRT:
32468d75effSDimitry Andric       return "ABRT";
32568d75effSDimitry Andric     case SIGSEGV:
32668d75effSDimitry Andric       return "SEGV";
32768d75effSDimitry Andric     case SIGBUS:
32868d75effSDimitry Andric       return "BUS";
32968d75effSDimitry Andric     case SIGTRAP:
33068d75effSDimitry Andric       return "TRAP";
33168d75effSDimitry Andric   }
33268d75effSDimitry Andric   return "UNKNOWN SIGNAL";
33368d75effSDimitry Andric }
33468d75effSDimitry Andric 
33568d75effSDimitry Andric fd_t ReserveStandardFds(fd_t fd) {
33668d75effSDimitry Andric   CHECK_GE(fd, 0);
33768d75effSDimitry Andric   if (fd > 2)
33868d75effSDimitry Andric     return fd;
33968d75effSDimitry Andric   bool used[3];
34068d75effSDimitry Andric   internal_memset(used, 0, sizeof(used));
34168d75effSDimitry Andric   while (fd <= 2) {
34268d75effSDimitry Andric     used[fd] = true;
34368d75effSDimitry Andric     fd = internal_dup(fd);
34468d75effSDimitry Andric   }
34568d75effSDimitry Andric   for (int i = 0; i <= 2; ++i)
34668d75effSDimitry Andric     if (used[i])
34768d75effSDimitry Andric       internal_close(i);
34868d75effSDimitry Andric   return fd;
34968d75effSDimitry Andric }
35068d75effSDimitry Andric 
35168d75effSDimitry Andric bool ShouldMockFailureToOpen(const char *path) {
35268d75effSDimitry Andric   return common_flags()->test_only_emulate_no_memorymap &&
35368d75effSDimitry Andric          internal_strncmp(path, "/proc/", 6) == 0;
35468d75effSDimitry Andric }
35568d75effSDimitry Andric 
35668d75effSDimitry Andric #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
35768d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
35868d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
35968d75effSDimitry Andric     return -1;
36068d75effSDimitry Andric   char shmname[200];
36168d75effSDimitry Andric   CHECK(internal_strlen(name) < sizeof(shmname) - 10);
36268d75effSDimitry Andric   internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
36368d75effSDimitry Andric                     internal_getpid(), name);
3645ffd83dbSDimitry Andric   int o_cloexec = 0;
3655ffd83dbSDimitry Andric #if defined(O_CLOEXEC)
3665ffd83dbSDimitry Andric   o_cloexec = O_CLOEXEC;
3675ffd83dbSDimitry Andric #endif
36868d75effSDimitry Andric   int fd = ReserveStandardFds(
3695ffd83dbSDimitry Andric       internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
37068d75effSDimitry Andric   CHECK_GE(fd, 0);
37168d75effSDimitry Andric   int res = internal_ftruncate(fd, size);
372e8d8bef9SDimitry Andric #if !defined(O_CLOEXEC)
373e8d8bef9SDimitry Andric   res = fcntl(fd, F_SETFD, FD_CLOEXEC);
374e8d8bef9SDimitry Andric   CHECK_EQ(0, res);
375e8d8bef9SDimitry Andric #endif
37668d75effSDimitry Andric   CHECK_EQ(0, res);
37768d75effSDimitry Andric   res = internal_unlink(shmname);
37868d75effSDimitry Andric   CHECK_EQ(0, res);
37968d75effSDimitry Andric   *flags &= ~(MAP_ANON | MAP_ANONYMOUS);
38068d75effSDimitry Andric   return fd;
38168d75effSDimitry Andric }
38268d75effSDimitry Andric #else
38368d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
38468d75effSDimitry Andric   return -1;
38568d75effSDimitry Andric }
38668d75effSDimitry Andric #endif
38768d75effSDimitry Andric 
38868d75effSDimitry Andric #if SANITIZER_ANDROID
38968d75effSDimitry Andric #define PR_SET_VMA 0x53564d41
39068d75effSDimitry Andric #define PR_SET_VMA_ANON_NAME 0
39168d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
39268d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
39368d75effSDimitry Andric     return;
39468d75effSDimitry Andric   internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name);
39568d75effSDimitry Andric }
39668d75effSDimitry Andric #else
39768d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
39868d75effSDimitry Andric }
39968d75effSDimitry Andric #endif
40068d75effSDimitry Andric 
40168d75effSDimitry Andric uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) {
40268d75effSDimitry Andric   int fd = GetNamedMappingFd(name, length, &flags);
40368d75effSDimitry Andric   uptr res = internal_mmap(addr, length, prot, flags, fd, 0);
40468d75effSDimitry Andric   if (!internal_iserror(res))
40568d75effSDimitry Andric     DecorateMapping(res, length, name);
40668d75effSDimitry Andric   return res;
40768d75effSDimitry Andric }
40868d75effSDimitry Andric 
40968d75effSDimitry Andric 
41068d75effSDimitry Andric } // namespace __sanitizer
41168d75effSDimitry Andric 
41268d75effSDimitry Andric #endif // SANITIZER_POSIX
413