1 //===-- sanitizer_posix.cc ------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries and implements POSIX-specific functions from
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
17 #include "sanitizer_common.h"
18 #include "sanitizer_file.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_posix.h"
21 #include "sanitizer_procmaps.h"
29 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
30 // that, it was never implemented. So just define it to zero.
32 #define MAP_NORESERVE 0
35 namespace __sanitizer
{
37 // ------------- sanitizer_common.h
38 uptr
GetMmapGranularity() {
42 void *MmapOrDie(uptr size
, const char *mem_type
, bool raw_report
) {
43 size
= RoundUpTo(size
, GetPageSizeCached());
44 uptr res
= internal_mmap(nullptr, size
,
45 PROT_READ
| PROT_WRITE
,
46 MAP_PRIVATE
| MAP_ANON
, -1, 0);
48 if (UNLIKELY(internal_iserror(res
, &reserrno
)))
49 ReportMmapFailureAndDie(size
, mem_type
, "allocate", reserrno
, raw_report
);
50 IncreaseTotalMmap(size
);
54 void UnmapOrDie(void *addr
, uptr size
) {
55 if (!addr
|| !size
) return;
56 uptr res
= internal_munmap(addr
, size
);
57 if (UNLIKELY(internal_iserror(res
))) {
58 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
59 SanitizerToolName
, size
, size
, addr
);
60 CHECK("unable to unmap" && 0);
62 DecreaseTotalMmap(size
);
65 void *MmapOrDieOnFatalError(uptr size
, const char *mem_type
) {
66 size
= RoundUpTo(size
, GetPageSizeCached());
67 uptr res
= internal_mmap(nullptr, size
,
68 PROT_READ
| PROT_WRITE
,
69 MAP_PRIVATE
| MAP_ANON
, -1, 0);
71 if (UNLIKELY(internal_iserror(res
, &reserrno
))) {
72 if (reserrno
== ENOMEM
)
74 ReportMmapFailureAndDie(size
, mem_type
, "allocate", reserrno
);
76 IncreaseTotalMmap(size
);
80 // We want to map a chunk of address space aligned to 'alignment'.
81 // We do it by mapping a bit more and then unmapping redundant pieces.
82 // We probably can do it with fewer syscalls in some OS-dependent way.
83 void *MmapAlignedOrDieOnFatalError(uptr size
, uptr alignment
,
84 const char *mem_type
) {
85 CHECK(IsPowerOfTwo(size
));
86 CHECK(IsPowerOfTwo(alignment
));
87 uptr map_size
= size
+ alignment
;
88 uptr map_res
= (uptr
)MmapOrDieOnFatalError(map_size
, mem_type
);
89 if (UNLIKELY(!map_res
))
91 uptr map_end
= map_res
+ map_size
;
93 if (!IsAligned(res
, alignment
)) {
94 res
= (map_res
+ alignment
- 1) & ~(alignment
- 1);
95 UnmapOrDie((void*)map_res
, res
- map_res
);
97 uptr end
= res
+ size
;
99 UnmapOrDie((void*)end
, map_end
- end
);
103 void *MmapNoReserveOrDie(uptr size
, const char *mem_type
) {
104 uptr PageSize
= GetPageSizeCached();
105 uptr p
= internal_mmap(nullptr,
106 RoundUpTo(size
, PageSize
),
107 PROT_READ
| PROT_WRITE
,
108 MAP_PRIVATE
| MAP_ANON
| MAP_NORESERVE
,
111 if (UNLIKELY(internal_iserror(p
, &reserrno
)))
112 ReportMmapFailureAndDie(size
, mem_type
, "allocate noreserve", reserrno
);
113 IncreaseTotalMmap(size
);
117 void *MmapFixedImpl(uptr fixed_addr
, uptr size
, bool tolerate_enomem
) {
118 uptr PageSize
= GetPageSizeCached();
119 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
120 RoundUpTo(size
, PageSize
),
121 PROT_READ
| PROT_WRITE
,
122 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
125 if (UNLIKELY(internal_iserror(p
, &reserrno
))) {
126 if (tolerate_enomem
&& reserrno
== ENOMEM
)
129 internal_snprintf(mem_type
, sizeof(mem_type
), "memory at address 0x%zx",
131 ReportMmapFailureAndDie(size
, mem_type
, "allocate", reserrno
);
133 IncreaseTotalMmap(size
);
137 void *MmapFixedOrDie(uptr fixed_addr
, uptr size
) {
138 return MmapFixedImpl(fixed_addr
, size
, false /*tolerate_enomem*/);
141 void *MmapFixedOrDieOnFatalError(uptr fixed_addr
, uptr size
) {
142 return MmapFixedImpl(fixed_addr
, size
, true /*tolerate_enomem*/);
145 bool MprotectNoAccess(uptr addr
, uptr size
) {
146 return 0 == internal_mprotect((void*)addr
, size
, PROT_NONE
);
149 bool MprotectReadOnly(uptr addr
, uptr size
) {
150 return 0 == internal_mprotect((void *)addr
, size
, PROT_READ
);
154 void MprotectMallocZones(void *addr
, int prot
) {}
157 fd_t
OpenFile(const char *filename
, FileAccessMode mode
, error_t
*errno_p
) {
160 case RdOnly
: flags
= O_RDONLY
; break;
161 case WrOnly
: flags
= O_WRONLY
| O_CREAT
| O_TRUNC
; break;
162 case RdWr
: flags
= O_RDWR
| O_CREAT
; break;
164 fd_t res
= internal_open(filename
, flags
, 0660);
165 if (internal_iserror(res
, errno_p
))
170 void CloseFile(fd_t fd
) {
174 bool ReadFromFile(fd_t fd
, void *buff
, uptr buff_size
, uptr
*bytes_read
,
176 uptr res
= internal_read(fd
, buff
, buff_size
);
177 if (internal_iserror(res
, error_p
))
184 bool WriteToFile(fd_t fd
, const void *buff
, uptr buff_size
, uptr
*bytes_written
,
186 uptr res
= internal_write(fd
, buff
, buff_size
);
187 if (internal_iserror(res
, error_p
))
190 *bytes_written
= res
;
194 bool RenameFile(const char *oldpath
, const char *newpath
, error_t
*error_p
) {
195 uptr res
= internal_rename(oldpath
, newpath
);
196 return !internal_iserror(res
, error_p
);
199 void *MapFileToMemory(const char *file_name
, uptr
*buff_size
) {
200 fd_t fd
= OpenFile(file_name
, RdOnly
);
201 CHECK(fd
!= kInvalidFd
);
202 uptr fsize
= internal_filesize(fd
);
203 CHECK_NE(fsize
, (uptr
)-1);
205 *buff_size
= RoundUpTo(fsize
, GetPageSizeCached());
206 uptr map
= internal_mmap(nullptr, *buff_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
207 return internal_iserror(map
) ? nullptr : (void *)map
;
210 void *MapWritableFileToMemory(void *addr
, uptr size
, fd_t fd
, OFF_T offset
) {
211 uptr flags
= MAP_SHARED
;
212 if (addr
) flags
|= MAP_FIXED
;
213 uptr p
= internal_mmap(addr
, size
, PROT_READ
| PROT_WRITE
, flags
, fd
, offset
);
215 if (internal_iserror(p
, &mmap_errno
)) {
216 Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
217 fd
, (long long)offset
, size
, p
, mmap_errno
);
223 static inline bool IntervalsAreSeparate(uptr start1
, uptr end1
,
224 uptr start2
, uptr end2
) {
225 CHECK(start1
<= end1
);
226 CHECK(start2
<= end2
);
227 return (end1
< start2
) || (end2
< start1
);
230 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
231 // When the shadow is mapped only a single thread usually exists (plus maybe
232 // several worker threads on Mac, which aren't expected to map big chunks of
234 bool MemoryRangeIsAvailable(uptr range_start
, uptr range_end
) {
235 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
236 MemoryMappedSegment segment
;
237 while (proc_maps
.Next(&segment
)) {
238 if (segment
.start
== segment
.end
) continue; // Empty range.
239 CHECK_NE(0, segment
.end
);
240 if (!IntervalsAreSeparate(segment
.start
, segment
.end
- 1, range_start
,
247 void DumpProcessMap() {
248 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
249 const sptr kBufSize
= 4095;
250 char *filename
= (char*)MmapOrDie(kBufSize
, __func__
);
251 MemoryMappedSegment
segment(filename
, kBufSize
);
252 Report("Process memory map follows:\n");
253 while (proc_maps
.Next(&segment
)) {
254 Printf("\t%p-%p\t%s\n", (void *)segment
.start
, (void *)segment
.end
,
257 Report("End of process memory map.\n");
258 UnmapOrDie(filename
, kBufSize
);
261 const char *GetPwd() {
262 return GetEnv("PWD");
265 bool IsPathSeparator(const char c
) {
269 bool IsAbsolutePath(const char *path
) {
270 return path
!= nullptr && IsPathSeparator(path
[0]);
273 void ReportFile::Write(const char *buffer
, uptr length
) {
275 static const char *kWriteError
=
276 "ReportFile::Write() can't output requested buffer!\n";
278 if (length
!= internal_write(fd
, buffer
, length
)) {
279 internal_write(fd
, kWriteError
, internal_strlen(kWriteError
));
284 bool GetCodeRangeForFile(const char *module
, uptr
*start
, uptr
*end
) {
285 MemoryMappingLayout
proc_maps(/*cache_enabled*/false);
286 InternalScopedString
buff(kMaxPathLength
);
287 MemoryMappedSegment
segment(buff
.data(), kMaxPathLength
);
288 while (proc_maps
.Next(&segment
)) {
289 if (segment
.IsExecutable() &&
290 internal_strcmp(module
, segment
.filename
) == 0) {
291 *start
= segment
.start
;
299 uptr
SignalContext::GetAddress() const {
300 auto si
= static_cast<const siginfo_t
*>(siginfo
);
301 return (uptr
)si
->si_addr
;
304 bool SignalContext::IsMemoryAccess() const {
305 auto si
= static_cast<const siginfo_t
*>(siginfo
);
306 return si
->si_signo
== SIGSEGV
;
309 int SignalContext::GetType() const {
310 return static_cast<const siginfo_t
*>(siginfo
)->si_signo
;
313 const char *SignalContext::Describe() const {
326 return "UNKNOWN SIGNAL";
329 } // namespace __sanitizer
331 #endif // SANITIZER_POSIX