sanitizer_posix.cc revision 4df343a31cf57c309cf102b9aef870458318f579
1//===-- sanitizer_posix.cc ------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is shared between AddressSanitizer and ThreadSanitizer 11// run-time libraries and implements POSIX-specific functions from 12// sanitizer_libc.h. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_platform.h" 16#if SANITIZER_LINUX || SANITIZER_MAC 17 18#include "sanitizer_common.h" 19#include "sanitizer_libc.h" 20#include "sanitizer_procmaps.h" 21#include "sanitizer_stacktrace.h" 22 23#include <errno.h> 24#include <pthread.h> 25#include <stdarg.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <sys/mman.h> 30#include <sys/resource.h> 31#include <sys/time.h> 32#include <sys/types.h> 33#include <unistd.h> 34 35namespace __sanitizer { 36 37// ------------- sanitizer_common.h 38uptr GetMmapGranularity() { 39 return GetPageSize(); 40} 41 42u32 GetUid() { 43 return getuid(); 44} 45 46uptr GetThreadSelf() { 47 return (uptr)pthread_self(); 48} 49 50void *MmapOrDie(uptr size, const char *mem_type) { 51 size = RoundUpTo(size, GetPageSizeCached()); 52 uptr res = internal_mmap(0, size, 53 PROT_READ | PROT_WRITE, 54 MAP_PRIVATE | MAP_ANON, -1, 0); 55 int reserrno; 56 if (internal_iserror(res, &reserrno)) { 57 static int recursion_count; 58 if (recursion_count) { 59 // The Report() and CHECK calls below may call mmap recursively and fail. 60 // If we went into recursion, just die. 61 RawWrite("ERROR: Failed to mmap\n"); 62 Die(); 63 } 64 recursion_count++; 65 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n", 66 SanitizerToolName, size, size, mem_type, reserrno); 67 DumpProcessMap(); 68 CHECK("unable to mmap" && 0); 69 } 70 return (void *)res; 71} 72 73void UnmapOrDie(void *addr, uptr size) { 74 if (!addr || !size) return; 75 uptr res = internal_munmap(addr, size); 76 if (internal_iserror(res)) { 77 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 78 SanitizerToolName, size, size, addr); 79 CHECK("unable to unmap" && 0); 80 } 81} 82 83void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 84 uptr PageSize = GetPageSizeCached(); 85 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 86 RoundUpTo(size, PageSize), 87 PROT_READ | PROT_WRITE, 88 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 89 -1, 0); 90 int reserrno; 91 if (internal_iserror(p, &reserrno)) 92 Report("ERROR: " 93 "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 94 SanitizerToolName, size, size, fixed_addr, reserrno); 95 return (void *)p; 96} 97 98void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 99 uptr PageSize = GetPageSizeCached(); 100 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 101 RoundUpTo(size, PageSize), 102 PROT_READ | PROT_WRITE, 103 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 104 -1, 0); 105 int reserrno; 106 if (internal_iserror(p, &reserrno)) { 107 Report("ERROR:" 108 " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 109 SanitizerToolName, size, size, fixed_addr, reserrno); 110 CHECK("unable to mmap" && 0); 111 } 112 return (void *)p; 113} 114 115void *Mprotect(uptr fixed_addr, uptr size) { 116 return (void *)internal_mmap((void*)fixed_addr, size, 117 PROT_NONE, 118 MAP_PRIVATE | MAP_ANON | MAP_FIXED | 119 MAP_NORESERVE, -1, 0); 120} 121 122void FlushUnneededShadowMemory(uptr addr, uptr size) { 123 madvise((void*)addr, size, MADV_DONTNEED); 124} 125 126void *MapFileToMemory(const char *file_name, uptr *buff_size) { 127 uptr openrv = OpenFile(file_name, false); 128 CHECK(!internal_iserror(openrv)); 129 fd_t fd = openrv; 130 uptr fsize = internal_filesize(fd); 131 CHECK_NE(fsize, (uptr)-1); 132 CHECK_GT(fsize, 0); 133 *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 134 uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 135 return internal_iserror(map) ? 0 : (void *)map; 136} 137 138 139static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 140 uptr start2, uptr end2) { 141 CHECK(start1 <= end1); 142 CHECK(start2 <= end2); 143 return (end1 < start2) || (end2 < start1); 144} 145 146// FIXME: this is thread-unsafe, but should not cause problems most of the time. 147// When the shadow is mapped only a single thread usually exists (plus maybe 148// several worker threads on Mac, which aren't expected to map big chunks of 149// memory). 150bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 151 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 152 uptr start, end; 153 while (proc_maps.Next(&start, &end, 154 /*offset*/0, /*filename*/0, /*filename_size*/0, 155 /*protection*/0)) { 156 if (!IntervalsAreSeparate(start, end, range_start, range_end)) 157 return false; 158 } 159 return true; 160} 161 162void DumpProcessMap() { 163 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 164 uptr start, end; 165 const sptr kBufSize = 4095; 166 char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__); 167 Report("Process memory map follows:\n"); 168 while (proc_maps.Next(&start, &end, /* file_offset */0, 169 filename, kBufSize, /* protection */0)) { 170 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 171 } 172 Report("End of process memory map.\n"); 173 UnmapOrDie(filename, kBufSize); 174} 175 176const char *GetPwd() { 177 return GetEnv("PWD"); 178} 179 180void DisableCoreDumper() { 181 struct rlimit nocore; 182 nocore.rlim_cur = 0; 183 nocore.rlim_max = 0; 184 setrlimit(RLIMIT_CORE, &nocore); 185} 186 187bool StackSizeIsUnlimited() { 188 struct rlimit rlim; 189 CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim)); 190 return (rlim.rlim_cur == (uptr)-1); 191} 192 193void SetStackSizeLimitInBytes(uptr limit) { 194 struct rlimit rlim; 195 rlim.rlim_cur = limit; 196 rlim.rlim_max = limit; 197 if (setrlimit(RLIMIT_STACK, &rlim)) { 198 Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); 199 Die(); 200 } 201 CHECK(!StackSizeIsUnlimited()); 202} 203 204void SleepForSeconds(int seconds) { 205 sleep(seconds); 206} 207 208void SleepForMillis(int millis) { 209 usleep(millis * 1000); 210} 211 212void Abort() { 213 abort(); 214} 215 216int Atexit(void (*function)(void)) { 217#ifndef SANITIZER_GO 218 return atexit(function); 219#else 220 return 0; 221#endif 222} 223 224int internal_isatty(fd_t fd) { 225 return isatty(fd); 226} 227 228#ifndef SANITIZER_GO 229void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, 230 uptr stack_top, uptr stack_bottom, bool fast) { 231#if !SANITIZER_CAN_FAST_UNWIND 232 fast = false; 233#endif 234#if SANITIZER_MAC 235 // Always unwind fast on Mac. 236 (void)fast; 237#else 238 if (!fast || (stack_top == stack_bottom)) 239 return stack->SlowUnwindStack(pc, max_s); 240#endif // SANITIZER_MAC 241 stack->size = 0; 242 stack->trace[0] = pc; 243 if (max_s > 1) { 244 stack->max_size = max_s; 245 stack->FastUnwindStack(pc, bp, stack_top, stack_bottom); 246 } 247} 248#endif // SANITIZER_GO 249 250} // namespace __sanitizer 251 252#endif // SANITIZER_LINUX || SANITIZER_MAC 253