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__)
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 return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
87 # elif defined(__aarch64__)
88 return (1ULL << 39) - 1;
89 # elif defined(__mips64)
90 return (1ULL << 40) - 1;
92 return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
94 #else // SANITIZER_WORDSIZE == 32
95 uptr res
= (1ULL << 32) - 1; // 0xffffffff;
96 if (!common_flags()->full_address_space
)
97 res
-= GetKernelAreaSize();
98 CHECK_LT(reinterpret_cast<uptr
>(&res
), res
);
100 #endif // SANITIZER_WORDSIZE
103 void *MmapOrDie(uptr size
, const char *mem_type
) {
104 size
= RoundUpTo(size
, GetPageSizeCached());
105 uptr res
= internal_mmap(0, size
,
106 PROT_READ
| PROT_WRITE
,
107 MAP_PRIVATE
| MAP_ANON
, -1, 0);
109 if (internal_iserror(res
, &reserrno
)) {
110 static int recursion_count
;
111 if (recursion_count
) {
112 // The Report() and CHECK calls below may call mmap recursively and fail.
113 // If we went into recursion, just die.
114 RawWrite("ERROR: Failed to mmap\n");
118 Report("ERROR: %s failed to "
119 "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
120 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
122 CHECK("unable to mmap" && 0);
124 IncreaseTotalMmap(size
);
128 void UnmapOrDie(void *addr
, uptr size
) {
129 if (!addr
|| !size
) return;
130 uptr res
= internal_munmap(addr
, size
);
131 if (internal_iserror(res
)) {
132 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
133 SanitizerToolName
, size
, size
, addr
);
134 CHECK("unable to unmap" && 0);
136 DecreaseTotalMmap(size
);
139 void *MmapNoReserveOrDie(uptr size
, const char *mem_type
) {
140 uptr PageSize
= GetPageSizeCached();
141 uptr p
= internal_mmap(0,
142 RoundUpTo(size
, PageSize
),
143 PROT_READ
| PROT_WRITE
,
144 MAP_PRIVATE
| MAP_ANON
| MAP_NORESERVE
,
147 if (internal_iserror(p
, &reserrno
)) {
148 Report("ERROR: %s failed to "
149 "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
150 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
151 CHECK("unable to mmap" && 0);
153 IncreaseTotalMmap(size
);
157 void *MmapFixedNoReserve(uptr fixed_addr
, uptr size
) {
158 uptr PageSize
= GetPageSizeCached();
159 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
160 RoundUpTo(size
, PageSize
),
161 PROT_READ
| PROT_WRITE
,
162 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
| MAP_NORESERVE
,
165 if (internal_iserror(p
, &reserrno
))
166 Report("ERROR: %s failed to "
167 "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
168 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
169 IncreaseTotalMmap(size
);
173 void *MmapFixedOrDie(uptr fixed_addr
, uptr size
) {
174 uptr PageSize
= GetPageSizeCached();
175 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
176 RoundUpTo(size
, PageSize
),
177 PROT_READ
| PROT_WRITE
,
178 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
181 if (internal_iserror(p
, &reserrno
)) {
182 Report("ERROR: %s failed to "
183 "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
184 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
185 CHECK("unable to mmap" && 0);
187 IncreaseTotalMmap(size
);
191 void *Mprotect(uptr fixed_addr
, uptr size
) {
192 return (void *)internal_mmap((void*)fixed_addr
, size
,
194 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
|
195 MAP_NORESERVE
, -1, 0);
198 void *MapFileToMemory(const char *file_name
, uptr
*buff_size
) {
199 uptr openrv
= OpenFile(file_name
, false);
200 CHECK(!internal_iserror(openrv
));
202 uptr fsize
= internal_filesize(fd
);
203 CHECK_NE(fsize
, (uptr
)-1);
205 *buff_size
= RoundUpTo(fsize
, GetPageSizeCached());
206 uptr map
= internal_mmap(0, *buff_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
207 return internal_iserror(map
) ? 0 : (void *)map
;
210 void *MapWritableFileToMemory(void *addr
, uptr size
, uptr fd
, uptr 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
);
214 if (internal_iserror(p
)) {
215 Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd
, offset
,
222 static inline bool IntervalsAreSeparate(uptr start1
, uptr end1
,
223 uptr start2
, uptr end2
) {
224 CHECK(start1
<= end1
);
225 CHECK(start2
<= end2
);
226 return (end1
< start2
) || (end2
< start1
);
229 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
230 // When the shadow is mapped only a single thread usually exists (plus maybe
231 // several worker threads on Mac, which aren't expected to map big chunks of
233 bool MemoryRangeIsAvailable(uptr range_start
, uptr range_end
) {
234 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
236 while (proc_maps
.Next(&start
, &end
,
237 /*offset*/0, /*filename*/0, /*filename_size*/0,
239 if (!IntervalsAreSeparate(start
, end
, range_start
, range_end
))
245 void DumpProcessMap() {
246 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
248 const sptr kBufSize
= 4095;
249 char *filename
= (char*)MmapOrDie(kBufSize
, __func__
);
250 Report("Process memory map follows:\n");
251 while (proc_maps
.Next(&start
, &end
, /* file_offset */0,
252 filename
, kBufSize
, /* protection */0)) {
253 Printf("\t%p-%p\t%s\n", (void*)start
, (void*)end
, filename
);
255 Report("End of process memory map.\n");
256 UnmapOrDie(filename
, kBufSize
);
259 const char *GetPwd() {
260 return GetEnv("PWD");
263 char *FindPathToBinary(const char *name
) {
264 const char *path
= GetEnv("PATH");
267 uptr name_len
= internal_strlen(name
);
268 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
269 const char *beg
= path
;
271 const char *end
= internal_strchrnul(beg
, ':');
272 uptr prefix_len
= end
- beg
;
273 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
274 internal_memcpy(buffer
.data(), beg
, prefix_len
);
275 buffer
[prefix_len
] = '/';
276 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
277 buffer
[prefix_len
+ 1 + name_len
] = '\0';
278 if (FileExists(buffer
.data()))
279 return internal_strdup(buffer
.data());
281 if (*end
== '\0') break;
287 void MaybeOpenReportFile() {
288 if (!log_to_file
) return;
289 uptr pid
= internal_getpid();
290 // If in tracer, use the parent's file.
291 if (pid
== stoptheworld_tracer_pid
)
292 pid
= stoptheworld_tracer_ppid
;
293 if (report_fd_pid
== pid
) return;
294 InternalScopedBuffer
<char> report_path_full(4096);
295 internal_snprintf(report_path_full
.data(), report_path_full
.size(),
296 "%s.%zu", report_path_prefix
, pid
);
297 uptr openrv
= OpenFile(report_path_full
.data(), true);
298 if (internal_iserror(openrv
)) {
299 report_fd
= kStderrFd
;
301 Report("ERROR: Can't open file: %s\n", report_path_full
.data());
304 if (report_fd
!= kInvalidFd
) {
305 // We're in the child. Close the parent's log.
306 internal_close(report_fd
);
312 void RawWrite(const char *buffer
) {
313 static const char *kRawWriteError
=
314 "RawWrite can't output requested buffer!\n";
315 uptr length
= (uptr
)internal_strlen(buffer
);
316 MaybeOpenReportFile();
317 if (length
!= internal_write(report_fd
, buffer
, length
)) {
318 internal_write(report_fd
, kRawWriteError
, internal_strlen(kRawWriteError
));
323 bool GetCodeRangeForFile(const char *module
, uptr
*start
, uptr
*end
) {
324 uptr s
, e
, off
, prot
;
325 InternalScopedString
buff(4096);
326 MemoryMappingLayout
proc_maps(/*cache_enabled*/false);
327 while (proc_maps
.Next(&s
, &e
, &off
, buff
.data(), buff
.size(), &prot
)) {
328 if ((prot
& MemoryMappingLayout::kProtectionExecute
) != 0
329 && internal_strcmp(module
, buff
.data()) == 0) {
338 } // namespace __sanitizer
340 #endif // SANITIZER_POSIX