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"
16 #include "sanitizer_common.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_procmaps.h"
19 #include "sanitizer_stacktrace.h"
24 #include <sys/utsname.h>
27 #if SANITIZER_LINUX && !SANITIZER_ANDROID
28 #include <sys/personality.h>
31 namespace __sanitizer
{
33 // ------------- sanitizer_common.h
34 uptr
GetMmapGranularity() {
38 #if SANITIZER_WORDSIZE == 32
39 // Take care of unusable kernel area in top gigabyte.
40 static uptr
GetKernelAreaSize() {
42 const uptr gbyte
= 1UL << 30;
44 // Firstly check if there are writable segments
45 // mapped to top gigabyte (e.g. stack).
46 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
48 while (proc_maps
.Next(/*start*/0, &end
,
49 /*offset*/0, /*filename*/0,
50 /*filename_size*/0, &prot
)) {
51 if ((end
>= 3 * gbyte
)
52 && (prot
& MemoryMappingLayout::kProtectionWrite
) != 0)
56 #if !SANITIZER_ANDROID
57 // Even if nothing is mapped, top Gb may still be accessible
58 // if we are running on 64-bit kernel.
59 // Uname may report misleading results if personality type
60 // is modified (e.g. under schroot) so check this as well.
61 struct utsname uname_info
;
62 int pers
= personality(0xffffffffUL
);
63 if (!(pers
& PER_MASK
)
64 && uname(&uname_info
) == 0
65 && internal_strstr(uname_info
.machine
, "64"))
67 #endif // SANITIZER_ANDROID
69 // Top gigabyte is reserved for kernel.
73 #endif // SANITIZER_LINUX
75 #endif // SANITIZER_WORDSIZE == 32
77 uptr
GetMaxVirtualAddress() {
78 #if SANITIZER_WORDSIZE == 64
79 # if defined(__powerpc64__) || defined(__aarch64__)
80 // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
81 // We somehow need to figure out which one we are using now and choose
82 // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
83 // Note that with 'ulimit -s unlimited' the stack is moved away from the top
84 // of the address space, so simply checking the stack address is not enough.
85 // This should (does) work for both PowerPC64 Endian modes.
86 // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
87 return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
88 # elif defined(__mips64)
89 return (1ULL << 40) - 1;
91 return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
93 #else // SANITIZER_WORDSIZE == 32
94 uptr res
= (1ULL << 32) - 1; // 0xffffffff;
95 if (!common_flags()->full_address_space
)
96 res
-= GetKernelAreaSize();
97 CHECK_LT(reinterpret_cast<uptr
>(&res
), res
);
99 #endif // SANITIZER_WORDSIZE
102 void *MmapOrDie(uptr size
, const char *mem_type
) {
103 size
= RoundUpTo(size
, GetPageSizeCached());
104 uptr res
= internal_mmap(0, size
,
105 PROT_READ
| PROT_WRITE
,
106 MAP_PRIVATE
| MAP_ANON
, -1, 0);
108 if (internal_iserror(res
, &reserrno
)) {
109 static int recursion_count
;
110 if (recursion_count
) {
111 // The Report() and CHECK calls below may call mmap recursively and fail.
112 // If we went into recursion, just die.
113 RawWrite("ERROR: Failed to mmap\n");
117 Report("ERROR: %s failed to "
118 "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
119 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
121 CHECK("unable to mmap" && 0);
123 IncreaseTotalMmap(size
);
127 void UnmapOrDie(void *addr
, uptr size
) {
128 if (!addr
|| !size
) return;
129 uptr res
= internal_munmap(addr
, size
);
130 if (internal_iserror(res
)) {
131 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
132 SanitizerToolName
, size
, size
, addr
);
133 CHECK("unable to unmap" && 0);
135 DecreaseTotalMmap(size
);
138 void *MmapNoReserveOrDie(uptr size
, const char *mem_type
) {
139 uptr PageSize
= GetPageSizeCached();
140 uptr p
= internal_mmap(0,
141 RoundUpTo(size
, PageSize
),
142 PROT_READ
| PROT_WRITE
,
143 MAP_PRIVATE
| MAP_ANON
| MAP_NORESERVE
,
146 if (internal_iserror(p
, &reserrno
)) {
147 Report("ERROR: %s failed to "
148 "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
149 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
150 CHECK("unable to mmap" && 0);
152 IncreaseTotalMmap(size
);
156 void *MmapFixedNoReserve(uptr fixed_addr
, uptr size
) {
157 uptr PageSize
= GetPageSizeCached();
158 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
159 RoundUpTo(size
, PageSize
),
160 PROT_READ
| PROT_WRITE
,
161 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
| MAP_NORESERVE
,
164 if (internal_iserror(p
, &reserrno
))
165 Report("ERROR: %s failed to "
166 "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
167 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
168 IncreaseTotalMmap(size
);
172 void *MmapFixedOrDie(uptr fixed_addr
, uptr size
) {
173 uptr PageSize
= GetPageSizeCached();
174 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
175 RoundUpTo(size
, PageSize
),
176 PROT_READ
| PROT_WRITE
,
177 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
180 if (internal_iserror(p
, &reserrno
)) {
181 Report("ERROR: %s failed to "
182 "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
183 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
184 CHECK("unable to mmap" && 0);
186 IncreaseTotalMmap(size
);
190 void *Mprotect(uptr fixed_addr
, uptr size
) {
191 return (void *)internal_mmap((void*)fixed_addr
, size
,
193 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
|
194 MAP_NORESERVE
, -1, 0);
197 void *MapFileToMemory(const char *file_name
, uptr
*buff_size
) {
198 uptr openrv
= OpenFile(file_name
, false);
199 CHECK(!internal_iserror(openrv
));
201 uptr fsize
= internal_filesize(fd
);
202 CHECK_NE(fsize
, (uptr
)-1);
204 *buff_size
= RoundUpTo(fsize
, GetPageSizeCached());
205 uptr map
= internal_mmap(0, *buff_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
206 return internal_iserror(map
) ? 0 : (void *)map
;
209 void *MapWritableFileToMemory(void *addr
, uptr size
, uptr fd
, uptr offset
) {
210 uptr flags
= MAP_SHARED
;
211 if (addr
) flags
|= MAP_FIXED
;
212 uptr p
= internal_mmap(addr
, size
, PROT_READ
| PROT_WRITE
, flags
, fd
, offset
);
213 if (internal_iserror(p
)) {
214 Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd
, offset
,
221 static inline bool IntervalsAreSeparate(uptr start1
, uptr end1
,
222 uptr start2
, uptr end2
) {
223 CHECK(start1
<= end1
);
224 CHECK(start2
<= end2
);
225 return (end1
< start2
) || (end2
< start1
);
228 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
229 // When the shadow is mapped only a single thread usually exists (plus maybe
230 // several worker threads on Mac, which aren't expected to map big chunks of
232 bool MemoryRangeIsAvailable(uptr range_start
, uptr range_end
) {
233 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
235 while (proc_maps
.Next(&start
, &end
,
236 /*offset*/0, /*filename*/0, /*filename_size*/0,
238 if (!IntervalsAreSeparate(start
, end
, range_start
, range_end
))
244 void DumpProcessMap() {
245 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
247 const sptr kBufSize
= 4095;
248 char *filename
= (char*)MmapOrDie(kBufSize
, __func__
);
249 Report("Process memory map follows:\n");
250 while (proc_maps
.Next(&start
, &end
, /* file_offset */0,
251 filename
, kBufSize
, /* protection */0)) {
252 Printf("\t%p-%p\t%s\n", (void*)start
, (void*)end
, filename
);
254 Report("End of process memory map.\n");
255 UnmapOrDie(filename
, kBufSize
);
258 const char *GetPwd() {
259 return GetEnv("PWD");
262 char *FindPathToBinary(const char *name
) {
263 const char *path
= GetEnv("PATH");
266 uptr name_len
= internal_strlen(name
);
267 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
268 const char *beg
= path
;
270 const char *end
= internal_strchrnul(beg
, ':');
271 uptr prefix_len
= end
- beg
;
272 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
273 internal_memcpy(buffer
.data(), beg
, prefix_len
);
274 buffer
[prefix_len
] = '/';
275 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
276 buffer
[prefix_len
+ 1 + name_len
] = '\0';
277 if (FileExists(buffer
.data()))
278 return internal_strdup(buffer
.data());
280 if (*end
== '\0') break;
286 void MaybeOpenReportFile() {
287 if (!log_to_file
) return;
288 uptr pid
= internal_getpid();
289 // If in tracer, use the parent's file.
290 if (pid
== stoptheworld_tracer_pid
)
291 pid
= stoptheworld_tracer_ppid
;
292 if (report_fd_pid
== pid
) return;
293 InternalScopedBuffer
<char> report_path_full(4096);
294 internal_snprintf(report_path_full
.data(), report_path_full
.size(),
295 "%s.%zu", report_path_prefix
, pid
);
296 uptr openrv
= OpenFile(report_path_full
.data(), true);
297 if (internal_iserror(openrv
)) {
298 report_fd
= kStderrFd
;
300 Report("ERROR: Can't open file: %s\n", report_path_full
.data());
303 if (report_fd
!= kInvalidFd
) {
304 // We're in the child. Close the parent's log.
305 internal_close(report_fd
);
311 void RawWrite(const char *buffer
) {
312 static const char *kRawWriteError
=
313 "RawWrite can't output requested buffer!\n";
314 uptr length
= (uptr
)internal_strlen(buffer
);
315 MaybeOpenReportFile();
316 if (length
!= internal_write(report_fd
, buffer
, length
)) {
317 internal_write(report_fd
, kRawWriteError
, internal_strlen(kRawWriteError
));
322 bool GetCodeRangeForFile(const char *module
, uptr
*start
, uptr
*end
) {
323 uptr s
, e
, off
, prot
;
324 InternalScopedString
buff(4096);
325 MemoryMappingLayout
proc_maps(/*cache_enabled*/false);
326 while (proc_maps
.Next(&s
, &e
, &off
, buff
.data(), buff
.size(), &prot
)) {
327 if ((prot
& MemoryMappingLayout::kProtectionExecute
) != 0
328 && internal_strcmp(module
, buff
.data()) == 0) {
337 } // namespace __sanitizer
339 #endif // SANITIZER_POSIX