xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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 
4468d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
4568d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
4668d75effSDimitry Andric   uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
4768d75effSDimitry Andric                        MAP_PRIVATE | MAP_ANON, mem_type);
4868d75effSDimitry Andric   int reserrno;
4968d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno)))
5068d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
5168d75effSDimitry Andric   IncreaseTotalMmap(size);
5268d75effSDimitry Andric   return (void *)res;
5368d75effSDimitry Andric }
5468d75effSDimitry Andric 
5568d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) {
5668d75effSDimitry Andric   if (!addr || !size) return;
5768d75effSDimitry Andric   uptr res = internal_munmap(addr, size);
5868d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res))) {
5968d75effSDimitry Andric     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
6068d75effSDimitry Andric            SanitizerToolName, size, size, addr);
6168d75effSDimitry Andric     CHECK("unable to unmap" && 0);
6268d75effSDimitry Andric   }
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;
8868d75effSDimitry Andric   uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
8968d75effSDimitry Andric   if (UNLIKELY(!map_res))
9068d75effSDimitry Andric     return nullptr;
9168d75effSDimitry Andric   uptr map_end = map_res + map_size;
9268d75effSDimitry Andric   uptr res = map_res;
9368d75effSDimitry Andric   if (!IsAligned(res, alignment)) {
9468d75effSDimitry Andric     res = (map_res + alignment - 1) & ~(alignment - 1);
9568d75effSDimitry Andric     UnmapOrDie((void*)map_res, res - map_res);
9668d75effSDimitry Andric   }
9768d75effSDimitry Andric   uptr end = res + size;
9868d75effSDimitry Andric   if (end != map_end)
9968d75effSDimitry Andric     UnmapOrDie((void*)end, map_end - end);
10068d75effSDimitry Andric   return (void*)res;
10168d75effSDimitry Andric }
10268d75effSDimitry Andric 
10368d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
10468d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
10568d75effSDimitry Andric   uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
10668d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type);
10768d75effSDimitry Andric   int reserrno;
10868d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno)))
10968d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
11068d75effSDimitry Andric   IncreaseTotalMmap(size);
11168d75effSDimitry Andric   return (void *)p;
11268d75effSDimitry Andric }
11368d75effSDimitry Andric 
11468d75effSDimitry Andric static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem,
11568d75effSDimitry Andric                            const char *name) {
11668d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
11768d75effSDimitry Andric   fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached());
11868d75effSDimitry Andric   uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE,
11968d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_FIXED, name);
12068d75effSDimitry Andric   int reserrno;
12168d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno))) {
12268d75effSDimitry Andric     if (tolerate_enomem && reserrno == ENOMEM)
12368d75effSDimitry Andric       return nullptr;
12468d75effSDimitry Andric     char mem_type[40];
12568d75effSDimitry Andric     internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
12668d75effSDimitry Andric                       fixed_addr);
12768d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
12868d75effSDimitry Andric   }
12968d75effSDimitry Andric   IncreaseTotalMmap(size);
13068d75effSDimitry Andric   return (void *)p;
13168d75effSDimitry Andric }
13268d75effSDimitry Andric 
13368d75effSDimitry Andric void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
13468d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name);
13568d75effSDimitry Andric }
13668d75effSDimitry Andric 
13768d75effSDimitry Andric void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
13868d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name);
13968d75effSDimitry Andric }
14068d75effSDimitry Andric 
14168d75effSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
14268d75effSDimitry Andric   return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
14368d75effSDimitry Andric }
14468d75effSDimitry Andric 
14568d75effSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
14668d75effSDimitry Andric   return 0 == internal_mprotect((void *)addr, size, PROT_READ);
14768d75effSDimitry Andric }
14868d75effSDimitry Andric 
14968d75effSDimitry Andric #if !SANITIZER_MAC
15068d75effSDimitry Andric void MprotectMallocZones(void *addr, int prot) {}
15168d75effSDimitry Andric #endif
15268d75effSDimitry Andric 
15368d75effSDimitry Andric fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
15468d75effSDimitry Andric   if (ShouldMockFailureToOpen(filename))
15568d75effSDimitry Andric     return kInvalidFd;
15668d75effSDimitry Andric   int flags;
15768d75effSDimitry Andric   switch (mode) {
15868d75effSDimitry Andric     case RdOnly: flags = O_RDONLY; break;
15968d75effSDimitry Andric     case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
16068d75effSDimitry Andric     case RdWr: flags = O_RDWR | O_CREAT; break;
16168d75effSDimitry Andric   }
16268d75effSDimitry Andric   fd_t res = internal_open(filename, flags, 0660);
16368d75effSDimitry Andric   if (internal_iserror(res, errno_p))
16468d75effSDimitry Andric     return kInvalidFd;
16568d75effSDimitry Andric   return ReserveStandardFds(res);
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
16868d75effSDimitry Andric void CloseFile(fd_t fd) {
16968d75effSDimitry Andric   internal_close(fd);
17068d75effSDimitry Andric }
17168d75effSDimitry Andric 
17268d75effSDimitry Andric bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
17368d75effSDimitry Andric                   error_t *error_p) {
17468d75effSDimitry Andric   uptr res = internal_read(fd, buff, buff_size);
17568d75effSDimitry Andric   if (internal_iserror(res, error_p))
17668d75effSDimitry Andric     return false;
17768d75effSDimitry Andric   if (bytes_read)
17868d75effSDimitry Andric     *bytes_read = res;
17968d75effSDimitry Andric   return true;
18068d75effSDimitry Andric }
18168d75effSDimitry Andric 
18268d75effSDimitry Andric bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
18368d75effSDimitry Andric                  error_t *error_p) {
18468d75effSDimitry Andric   uptr res = internal_write(fd, buff, buff_size);
18568d75effSDimitry Andric   if (internal_iserror(res, error_p))
18668d75effSDimitry Andric     return false;
18768d75effSDimitry Andric   if (bytes_written)
18868d75effSDimitry Andric     *bytes_written = res;
18968d75effSDimitry Andric   return true;
19068d75effSDimitry Andric }
19168d75effSDimitry Andric 
19268d75effSDimitry Andric void *MapFileToMemory(const char *file_name, uptr *buff_size) {
19368d75effSDimitry Andric   fd_t fd = OpenFile(file_name, RdOnly);
19468d75effSDimitry Andric   CHECK(fd != kInvalidFd);
19568d75effSDimitry Andric   uptr fsize = internal_filesize(fd);
19668d75effSDimitry Andric   CHECK_NE(fsize, (uptr)-1);
19768d75effSDimitry Andric   CHECK_GT(fsize, 0);
19868d75effSDimitry Andric   *buff_size = RoundUpTo(fsize, GetPageSizeCached());
19968d75effSDimitry Andric   uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
20068d75effSDimitry Andric   return internal_iserror(map) ? nullptr : (void *)map;
20168d75effSDimitry Andric }
20268d75effSDimitry Andric 
20368d75effSDimitry Andric void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
20468d75effSDimitry Andric   uptr flags = MAP_SHARED;
20568d75effSDimitry Andric   if (addr) flags |= MAP_FIXED;
20668d75effSDimitry Andric   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
20768d75effSDimitry Andric   int mmap_errno = 0;
20868d75effSDimitry Andric   if (internal_iserror(p, &mmap_errno)) {
20968d75effSDimitry Andric     Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
21068d75effSDimitry Andric            fd, (long long)offset, size, p, mmap_errno);
21168d75effSDimitry Andric     return nullptr;
21268d75effSDimitry Andric   }
21368d75effSDimitry Andric   return (void *)p;
21468d75effSDimitry Andric }
21568d75effSDimitry Andric 
21668d75effSDimitry Andric static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
21768d75effSDimitry Andric                                         uptr start2, uptr end2) {
21868d75effSDimitry Andric   CHECK(start1 <= end1);
21968d75effSDimitry Andric   CHECK(start2 <= end2);
22068d75effSDimitry Andric   return (end1 < start2) || (end2 < start1);
22168d75effSDimitry Andric }
22268d75effSDimitry Andric 
22368d75effSDimitry Andric // FIXME: this is thread-unsafe, but should not cause problems most of the time.
22468d75effSDimitry Andric // When the shadow is mapped only a single thread usually exists (plus maybe
22568d75effSDimitry Andric // several worker threads on Mac, which aren't expected to map big chunks of
22668d75effSDimitry Andric // memory).
22768d75effSDimitry Andric bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
22868d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
22968d75effSDimitry Andric   if (proc_maps.Error())
23068d75effSDimitry Andric     return true; // and hope for the best
23168d75effSDimitry Andric   MemoryMappedSegment segment;
23268d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
23368d75effSDimitry Andric     if (segment.start == segment.end) continue;  // Empty range.
23468d75effSDimitry Andric     CHECK_NE(0, segment.end);
23568d75effSDimitry Andric     if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
23668d75effSDimitry Andric                               range_end))
23768d75effSDimitry Andric       return false;
23868d75effSDimitry Andric   }
23968d75effSDimitry Andric   return true;
24068d75effSDimitry Andric }
24168d75effSDimitry Andric 
24268d75effSDimitry Andric void DumpProcessMap() {
24368d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
24468d75effSDimitry Andric   const sptr kBufSize = 4095;
24568d75effSDimitry Andric   char *filename = (char*)MmapOrDie(kBufSize, __func__);
24668d75effSDimitry Andric   MemoryMappedSegment segment(filename, kBufSize);
24768d75effSDimitry Andric   Report("Process memory map follows:\n");
24868d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
24968d75effSDimitry Andric     Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
25068d75effSDimitry Andric            segment.filename);
25168d75effSDimitry Andric   }
25268d75effSDimitry Andric   Report("End of process memory map.\n");
25368d75effSDimitry Andric   UnmapOrDie(filename, kBufSize);
25468d75effSDimitry Andric }
25568d75effSDimitry Andric 
25668d75effSDimitry Andric const char *GetPwd() {
25768d75effSDimitry Andric   return GetEnv("PWD");
25868d75effSDimitry Andric }
25968d75effSDimitry Andric 
26068d75effSDimitry Andric bool IsPathSeparator(const char c) {
26168d75effSDimitry Andric   return c == '/';
26268d75effSDimitry Andric }
26368d75effSDimitry Andric 
26468d75effSDimitry Andric bool IsAbsolutePath(const char *path) {
26568d75effSDimitry Andric   return path != nullptr && IsPathSeparator(path[0]);
26668d75effSDimitry Andric }
26768d75effSDimitry Andric 
26868d75effSDimitry Andric void ReportFile::Write(const char *buffer, uptr length) {
26968d75effSDimitry Andric   SpinMutexLock l(mu);
27068d75effSDimitry Andric   ReopenIfNecessary();
27168d75effSDimitry Andric   internal_write(fd, buffer, length);
27268d75effSDimitry Andric }
27368d75effSDimitry Andric 
27468d75effSDimitry Andric bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
27568d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
27668d75effSDimitry Andric   InternalScopedString buff(kMaxPathLength);
27768d75effSDimitry Andric   MemoryMappedSegment segment(buff.data(), kMaxPathLength);
27868d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
27968d75effSDimitry Andric     if (segment.IsExecutable() &&
28068d75effSDimitry Andric         internal_strcmp(module, segment.filename) == 0) {
28168d75effSDimitry Andric       *start = segment.start;
28268d75effSDimitry Andric       *end = segment.end;
28368d75effSDimitry Andric       return true;
28468d75effSDimitry Andric     }
28568d75effSDimitry Andric   }
28668d75effSDimitry Andric   return false;
28768d75effSDimitry Andric }
28868d75effSDimitry Andric 
28968d75effSDimitry Andric uptr SignalContext::GetAddress() const {
29068d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
29168d75effSDimitry Andric   return (uptr)si->si_addr;
29268d75effSDimitry Andric }
29368d75effSDimitry Andric 
29468d75effSDimitry Andric bool SignalContext::IsMemoryAccess() const {
29568d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
29668d75effSDimitry Andric   return si->si_signo == SIGSEGV;
29768d75effSDimitry Andric }
29868d75effSDimitry Andric 
29968d75effSDimitry Andric int SignalContext::GetType() const {
30068d75effSDimitry Andric   return static_cast<const siginfo_t *>(siginfo)->si_signo;
30168d75effSDimitry Andric }
30268d75effSDimitry Andric 
30368d75effSDimitry Andric const char *SignalContext::Describe() const {
30468d75effSDimitry Andric   switch (GetType()) {
30568d75effSDimitry Andric     case SIGFPE:
30668d75effSDimitry Andric       return "FPE";
30768d75effSDimitry Andric     case SIGILL:
30868d75effSDimitry Andric       return "ILL";
30968d75effSDimitry Andric     case SIGABRT:
31068d75effSDimitry Andric       return "ABRT";
31168d75effSDimitry Andric     case SIGSEGV:
31268d75effSDimitry Andric       return "SEGV";
31368d75effSDimitry Andric     case SIGBUS:
31468d75effSDimitry Andric       return "BUS";
31568d75effSDimitry Andric     case SIGTRAP:
31668d75effSDimitry Andric       return "TRAP";
31768d75effSDimitry Andric   }
31868d75effSDimitry Andric   return "UNKNOWN SIGNAL";
31968d75effSDimitry Andric }
32068d75effSDimitry Andric 
32168d75effSDimitry Andric fd_t ReserveStandardFds(fd_t fd) {
32268d75effSDimitry Andric   CHECK_GE(fd, 0);
32368d75effSDimitry Andric   if (fd > 2)
32468d75effSDimitry Andric     return fd;
32568d75effSDimitry Andric   bool used[3];
32668d75effSDimitry Andric   internal_memset(used, 0, sizeof(used));
32768d75effSDimitry Andric   while (fd <= 2) {
32868d75effSDimitry Andric     used[fd] = true;
32968d75effSDimitry Andric     fd = internal_dup(fd);
33068d75effSDimitry Andric   }
33168d75effSDimitry Andric   for (int i = 0; i <= 2; ++i)
33268d75effSDimitry Andric     if (used[i])
33368d75effSDimitry Andric       internal_close(i);
33468d75effSDimitry Andric   return fd;
33568d75effSDimitry Andric }
33668d75effSDimitry Andric 
33768d75effSDimitry Andric bool ShouldMockFailureToOpen(const char *path) {
33868d75effSDimitry Andric   return common_flags()->test_only_emulate_no_memorymap &&
33968d75effSDimitry Andric          internal_strncmp(path, "/proc/", 6) == 0;
34068d75effSDimitry Andric }
34168d75effSDimitry Andric 
34268d75effSDimitry Andric #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
34368d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
34468d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
34568d75effSDimitry Andric     return -1;
34668d75effSDimitry Andric   char shmname[200];
34768d75effSDimitry Andric   CHECK(internal_strlen(name) < sizeof(shmname) - 10);
34868d75effSDimitry Andric   internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
34968d75effSDimitry Andric                     internal_getpid(), name);
350*5ffd83dbSDimitry Andric   int o_cloexec = 0;
351*5ffd83dbSDimitry Andric #if defined(O_CLOEXEC)
352*5ffd83dbSDimitry Andric   o_cloexec = O_CLOEXEC;
353*5ffd83dbSDimitry Andric #endif
35468d75effSDimitry Andric   int fd = ReserveStandardFds(
355*5ffd83dbSDimitry Andric       internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
35668d75effSDimitry Andric   CHECK_GE(fd, 0);
357*5ffd83dbSDimitry Andric   if (!o_cloexec) {
358*5ffd83dbSDimitry Andric     int res = fcntl(fd, F_SETFD, FD_CLOEXEC);
359*5ffd83dbSDimitry Andric     CHECK_EQ(0, res);
360*5ffd83dbSDimitry Andric   }
36168d75effSDimitry Andric   int res = internal_ftruncate(fd, size);
36268d75effSDimitry Andric   CHECK_EQ(0, res);
36368d75effSDimitry Andric   res = internal_unlink(shmname);
36468d75effSDimitry Andric   CHECK_EQ(0, res);
36568d75effSDimitry Andric   *flags &= ~(MAP_ANON | MAP_ANONYMOUS);
36668d75effSDimitry Andric   return fd;
36768d75effSDimitry Andric }
36868d75effSDimitry Andric #else
36968d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
37068d75effSDimitry Andric   return -1;
37168d75effSDimitry Andric }
37268d75effSDimitry Andric #endif
37368d75effSDimitry Andric 
37468d75effSDimitry Andric #if SANITIZER_ANDROID
37568d75effSDimitry Andric #define PR_SET_VMA 0x53564d41
37668d75effSDimitry Andric #define PR_SET_VMA_ANON_NAME 0
37768d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
37868d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
37968d75effSDimitry Andric     return;
38068d75effSDimitry Andric   internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name);
38168d75effSDimitry Andric }
38268d75effSDimitry Andric #else
38368d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
38468d75effSDimitry Andric }
38568d75effSDimitry Andric #endif
38668d75effSDimitry Andric 
38768d75effSDimitry Andric uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) {
38868d75effSDimitry Andric   int fd = GetNamedMappingFd(name, length, &flags);
38968d75effSDimitry Andric   uptr res = internal_mmap(addr, length, prot, flags, fd, 0);
39068d75effSDimitry Andric   if (!internal_iserror(res))
39168d75effSDimitry Andric     DecorateMapping(res, length, name);
39268d75effSDimitry Andric   return res;
39368d75effSDimitry Andric }
39468d75effSDimitry Andric 
39568d75effSDimitry Andric 
39668d75effSDimitry Andric } // namespace __sanitizer
39768d75effSDimitry Andric 
39868d75effSDimitry Andric #endif // SANITIZER_POSIX
399