sanitizer_posix.cc revision bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66
11f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===-- sanitizer_posix.cc ------------------------------------------------===//
21f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//
31f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//                     The LLVM Compiler Infrastructure
41f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//
51f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// This file is distributed under the University of Illinois Open Source
61f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// License. See LICENSE.TXT for details.
71f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//
81f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===----------------------------------------------------------------------===//
91f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//
101f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer
111f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// run-time libraries and implements POSIX-specific functions from
121f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// sanitizer_libc.h.
131f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===----------------------------------------------------------------------===//
1424e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov
1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_platform.h"
1624e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#if SANITIZER_LINUX || SANITIZER_MAC
171f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
18230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include "sanitizer_common.h"
191f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov#include "sanitizer_libc.h"
20be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov#include "sanitizer_procmaps.h"
21736cf49a46b3cc5aa1856762f85e6f2799c24e5aSergey Matveev#include "sanitizer_stacktrace.h"
221f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
23230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include <sys/mman.h>
241f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
251f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonovnamespace __sanitizer {
261f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
27be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov// ------------- sanitizer_common.h
28f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryanyuptr GetMmapGranularity() {
29f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  return GetPageSize();
30f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany}
31be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov
32bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanovuptr GetMaxVirtualAddress() {
33bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#if SANITIZER_WORDSIZE == 64
34bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# if defined(__powerpc64__)
35bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
36bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // We somehow need to figure our which one we are using now and choose
37bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
38bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
39bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // of the address space, so simply checking the stack address is not enough.
40bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
41bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# else
42bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
43bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# endif
44bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#else  // SANITIZER_WORDSIZE == 32
45bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // FIXME: We can probably lower this on Android?
46bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  return (1ULL << 32) - 1;  // 0xffffffff;
47bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#endif  // SANITIZER_WORDSIZE
48bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov}
49bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov
50a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonovvoid *MmapOrDie(uptr size, const char *mem_type) {
51f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  size = RoundUpTo(size, GetPageSizeCached());
529578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr res = internal_mmap(0, size,
53230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov                            PROT_READ | PROT_WRITE,
54230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov                            MAP_PRIVATE | MAP_ANON, -1, 0);
559578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
569578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(res, &reserrno)) {
57e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    static int recursion_count;
58e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    if (recursion_count) {
59e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      // The Report() and CHECK calls below may call mmap recursively and fail.
60e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      // If we went into recursion, just die.
61c8490e2a09cd415cc58fc8f3b63bebddce61c82dDmitry Vyukov      RawWrite("ERROR: Failed to mmap\n");
62e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      Die();
63e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    }
64e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    recursion_count++;
65a8d37a05f05341c60fe4508d79286a1b17aa3dc2Alexander Potapenko    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
669578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, mem_type, reserrno);
670aa04b3f432bc55e7c116d5280685ee3f243be8eKostya Serebryany    DumpProcessMap();
68a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov    CHECK("unable to mmap" && 0);
69230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  }
709578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)res;
71230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov}
72230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov
73230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonovvoid UnmapOrDie(void *addr, uptr size) {
74230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  if (!addr || !size) return;
759578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr res = internal_munmap(addr, size);
769578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(res)) {
77859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
78859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany           SanitizerToolName, size, size, addr);
79a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov    CHECK("unable to unmap" && 0);
80230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  }
81230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov}
82230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov
83f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonovvoid *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
84f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  uptr PageSize = GetPageSizeCached();
859578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
86f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany      RoundUpTo(size, PageSize),
876b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      PROT_READ | PROT_WRITE,
886b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
896b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      -1, 0);
909578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
919578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(p, &reserrno))
92859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany    Report("ERROR: "
93859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany           "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
949578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, fixed_addr, reserrno);
959578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)p;
96f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov}
97f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov
989bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryanyvoid *MmapFixedOrDie(uptr fixed_addr, uptr size) {
999bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany  uptr PageSize = GetPageSizeCached();
1009578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
1019bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      RoundUpTo(size, PageSize),
1029bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      PROT_READ | PROT_WRITE,
1039bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
1049bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      -1, 0);
1059578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
1069578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(p, &reserrno)) {
107859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany    Report("ERROR:"
108859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany           " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
1099578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, fixed_addr, reserrno);
1109bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany    CHECK("unable to mmap" && 0);
1119bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany  }
1129578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)p;
1139bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany}
1149bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany
115f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonovvoid *Mprotect(uptr fixed_addr, uptr size) {
1169578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)internal_mmap((void*)fixed_addr, size,
1179578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               PROT_NONE,
1189578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               MAP_PRIVATE | MAP_ANON | MAP_FIXED |
1199578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               MAP_NORESERVE, -1, 0);
120f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov}
121f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov
122a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonovvoid *MapFileToMemory(const char *file_name, uptr *buff_size) {
1239578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr openrv = OpenFile(file_name, false);
1249578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  CHECK(!internal_iserror(openrv));
1259578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  fd_t fd = openrv;
126a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  uptr fsize = internal_filesize(fd);
127a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  CHECK_NE(fsize, (uptr)-1);
128a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  CHECK_GT(fsize, 0);
129f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  *buff_size = RoundUpTo(fsize, GetPageSizeCached());
1309578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
1319578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_iserror(map) ? 0 : (void *)map;
132a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov}
133a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov
134a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov
135dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovstatic inline bool IntervalsAreSeparate(uptr start1, uptr end1,
136dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                                        uptr start2, uptr end2) {
137dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  CHECK(start1 <= end1);
138dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  CHECK(start2 <= end2);
139dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  return (end1 < start2) || (end2 < start1);
140dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov}
141dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov
142dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// FIXME: this is thread-unsafe, but should not cause problems most of the time.
143dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// When the shadow is mapped only a single thread usually exists (plus maybe
144dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// several worker threads on Mac, which aren't expected to map big chunks of
145dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// memory).
146dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovbool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
1479ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
148dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  uptr start, end;
1499ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  while (proc_maps.Next(&start, &end,
1509ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko                        /*offset*/0, /*filename*/0, /*filename_size*/0,
1519ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko                        /*protection*/0)) {
152dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov    if (!IntervalsAreSeparate(start, end, range_start, range_end))
153dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov      return false;
154dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  }
155dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  return true;
156dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov}
157dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov
158be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonovvoid DumpProcessMap() {
1599ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
160be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  uptr start, end;
161be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  const sptr kBufSize = 4095;
162b84ee029ada36949c30c57c5f701191783990574Alexey Samsonov  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
163be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  Report("Process memory map follows:\n");
164be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  while (proc_maps.Next(&start, &end, /* file_offset */0,
16545717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                        filename, kBufSize, /* protection */0)) {
166be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov    Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
167be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  }
168be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  Report("End of process memory map.\n");
169b84ee029ada36949c30c57c5f701191783990574Alexey Samsonov  UnmapOrDie(filename, kBufSize);
170be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov}
171be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov
1720969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonovconst char *GetPwd() {
1730969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov  return GetEnv("PWD");
1740969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov}
1750969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov
1761f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov}  // namespace __sanitizer
1771f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
178736cf49a46b3cc5aa1856762f85e6f2799c24e5aSergey Matveev#endif  // SANITIZER_LINUX || SANITIZER_MAC
179