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
GetMmapGranularity()4068d75effSDimitry Andric uptr GetMmapGranularity() {
4168d75effSDimitry Andric return GetPageSize();
4268d75effSDimitry Andric }
4368d75effSDimitry Andric
ErrorIsOOM(error_t err)4481ad6265SDimitry Andric bool ErrorIsOOM(error_t err) { return err == ENOMEM; }
4581ad6265SDimitry Andric
MmapOrDie(uptr size,const char * mem_type,bool raw_report)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
UnmapOrDie(void * addr,uptr size,bool raw_report)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
MmapOrDieOnFatalError(uptr size,const char * mem_type)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.
MmapAlignedOrDieOnFatalError(uptr size,uptr alignment,const char * mem_type)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
MmapNoReserveOrDie(uptr size,const char * mem_type)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
MmapFixedImpl(uptr fixed_addr,uptr size,bool tolerate_enomem,const char * name)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
MmapFixedOrDie(uptr fixed_addr,uptr size,const char * name)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
MmapFixedOrDieOnFatalError(uptr fixed_addr,uptr size,const char * name)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
MprotectNoAccess(uptr addr,uptr size)14968d75effSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
15068d75effSDimitry Andric return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
15168d75effSDimitry Andric }
15268d75effSDimitry Andric
MprotectReadOnly(uptr addr,uptr size)15368d75effSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
15468d75effSDimitry Andric return 0 == internal_mprotect((void *)addr, size, PROT_READ);
15568d75effSDimitry Andric }
15668d75effSDimitry Andric
MprotectReadWrite(uptr addr,uptr size)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
MprotectMallocZones(void * addr,int prot)16268d75effSDimitry Andric void MprotectMallocZones(void *addr, int prot) {}
16368d75effSDimitry Andric #endif
16468d75effSDimitry Andric
OpenFile(const char * filename,FileAccessMode mode,error_t * errno_p)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
CloseFile(fd_t fd)18068d75effSDimitry Andric void CloseFile(fd_t fd) {
18168d75effSDimitry Andric internal_close(fd);
18268d75effSDimitry Andric }
18368d75effSDimitry Andric
ReadFromFile(fd_t fd,void * buff,uptr buff_size,uptr * bytes_read,error_t * error_p)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
WriteToFile(fd_t fd,const void * buff,uptr buff_size,uptr * bytes_written,error_t * error_p)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
MapFileToMemory(const char * file_name,uptr * buff_size)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
MapWritableFileToMemory(void * addr,uptr size,fd_t fd,OFF_T offset)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
IntervalsAreSeparate(uptr start1,uptr end1,uptr start2,uptr end2)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).
MemoryRangeIsAvailable(uptr range_start,uptr range_end)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
DumpProcessMap()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
GetPwd()27068d75effSDimitry Andric const char *GetPwd() {
27168d75effSDimitry Andric return GetEnv("PWD");
27268d75effSDimitry Andric }
27368d75effSDimitry Andric
IsPathSeparator(const char c)27468d75effSDimitry Andric bool IsPathSeparator(const char c) {
27568d75effSDimitry Andric return c == '/';
27668d75effSDimitry Andric }
27768d75effSDimitry Andric
IsAbsolutePath(const char * path)27868d75effSDimitry Andric bool IsAbsolutePath(const char *path) {
27968d75effSDimitry Andric return path != nullptr && IsPathSeparator(path[0]);
28068d75effSDimitry Andric }
28168d75effSDimitry Andric
Write(const char * buffer,uptr length)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
GetCodeRangeForFile(const char * module,uptr * start,uptr * end)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
GetAddress() const30368d75effSDimitry 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
IsMemoryAccess() const30868d75effSDimitry 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
GetType() const31368d75effSDimitry Andric int SignalContext::GetType() const {
31468d75effSDimitry Andric return static_cast<const siginfo_t *>(siginfo)->si_signo;
31568d75effSDimitry Andric }
31668d75effSDimitry Andric
Describe() const31768d75effSDimitry 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
ReserveStandardFds(fd_t fd)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
ShouldMockFailureToOpen(const char * path)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
GetNamedMappingFd(const char * name,uptr size,int * flags)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
GetNamedMappingFd(const char * name,uptr size,int * flags)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
DecorateMapping(uptr addr,uptr size,const char * name)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
DecorateMapping(uptr addr,uptr size,const char * name)39768d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
39868d75effSDimitry Andric }
39968d75effSDimitry Andric #endif
40068d75effSDimitry Andric
MmapNamed(void * addr,uptr length,int prot,int flags,const char * name)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