1 //===-- tsan_platform_posix.cpp -------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer (TSan), a race detector. 10 // 11 // POSIX-specific code. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_platform.h" 15 #if SANITIZER_POSIX 16 17 #include "sanitizer_common/sanitizer_common.h" 18 #include "sanitizer_common/sanitizer_errno.h" 19 #include "sanitizer_common/sanitizer_libc.h" 20 #include "sanitizer_common/sanitizer_procmaps.h" 21 #include "tsan_platform.h" 22 #include "tsan_rtl.h" 23 24 namespace __tsan { 25 26 static const char kShadowMemoryMappingWarning[] = 27 "FATAL: %s can not madvise shadow region [%zx, %zx] with %s (errno: %d)\n"; 28 static const char kShadowMemoryMappingHint[] = 29 "HINT: if %s is not supported in your environment, you may set " 30 "TSAN_OPTIONS=%s=0\n"; 31 32 static void DontDumpShadow(uptr addr, uptr size) { 33 if (common_flags()->use_madv_dontdump) 34 if (!DontDumpShadowMemory(addr, size)) { 35 Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size, 36 "MADV_DONTDUMP", errno); 37 Printf(kShadowMemoryMappingHint, "MADV_DONTDUMP", "use_madv_dontdump"); 38 Die(); 39 } 40 } 41 42 #if !SANITIZER_GO 43 void InitializeShadowMemory() { 44 // Map memory shadow. 45 if (!MmapFixedSuperNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), 46 "shadow")) { 47 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); 48 Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); 49 Die(); 50 } 51 // This memory range is used for thread stacks and large user mmaps. 52 // Frequently a thread uses only a small part of stack and similarly 53 // a program uses a small part of large mmap. On some programs 54 // we see 20% memory usage reduction without huge pages for this range. 55 DontDumpShadow(ShadowBeg(), ShadowEnd() - ShadowBeg()); 56 DPrintf("memory shadow: %zx-%zx (%zuGB)\n", 57 ShadowBeg(), ShadowEnd(), 58 (ShadowEnd() - ShadowBeg()) >> 30); 59 60 // Map meta shadow. 61 const uptr meta = MetaShadowBeg(); 62 const uptr meta_size = MetaShadowEnd() - meta; 63 if (!MmapFixedSuperNoReserve(meta, meta_size, "meta shadow")) { 64 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); 65 Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); 66 Die(); 67 } 68 DontDumpShadow(meta, meta_size); 69 DPrintf("meta shadow: %zx-%zx (%zuGB)\n", 70 meta, meta + meta_size, meta_size >> 30); 71 72 InitializeShadowMemoryPlatform(); 73 } 74 75 static bool TryProtectRange(uptr beg, uptr end) { 76 CHECK_LE(beg, end); 77 if (beg == end) 78 return true; 79 return beg == (uptr)MmapFixedNoAccess(beg, end - beg); 80 } 81 82 static void ProtectRange(uptr beg, uptr end) { 83 if (!TryProtectRange(beg, end)) { 84 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end); 85 Printf("FATAL: Make sure you are not using unlimited stack\n"); 86 Die(); 87 } 88 } 89 90 void CheckAndProtect() { 91 // Ensure that the binary is indeed compiled with -pie. 92 MemoryMappingLayout proc_maps(true); 93 MemoryMappedSegment segment; 94 while (proc_maps.Next(&segment)) { 95 if (IsAppMem(segment.start)) continue; 96 if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue; 97 if (segment.protection == 0) // Zero page or mprotected. 98 continue; 99 if (segment.start >= VdsoBeg()) // vdso 100 break; 101 Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", 102 segment.start, segment.end); 103 Die(); 104 } 105 106 #if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE 107 ProtectRange(HeapMemEnd(), ShadowBeg()); 108 ProtectRange(ShadowEnd(), MetaShadowBeg()); 109 ProtectRange(MetaShadowEnd(), TraceMemBeg()); 110 #else 111 ProtectRange(LoAppMemEnd(), ShadowBeg()); 112 ProtectRange(ShadowEnd(), MetaShadowBeg()); 113 #ifdef TSAN_MID_APP_RANGE 114 ProtectRange(MetaShadowEnd(), MidAppMemBeg()); 115 ProtectRange(MidAppMemEnd(), TraceMemBeg()); 116 #else 117 ProtectRange(MetaShadowEnd(), TraceMemBeg()); 118 #endif 119 // Memory for traces is mapped lazily in MapThreadTrace. 120 // Protect the whole range for now, so that user does not map something here. 121 ProtectRange(TraceMemBeg(), TraceMemEnd()); 122 ProtectRange(TraceMemEnd(), HeapMemBeg()); 123 ProtectRange(HeapEnd(), HiAppMemBeg()); 124 #endif 125 126 #if defined(__s390x__) 127 // Protect the rest of the address space. 128 const uptr user_addr_max_l4 = 0x0020000000000000ull; 129 const uptr user_addr_max_l5 = 0xfffffffffffff000ull; 130 // All the maintained s390x kernels support at least 4-level page tables. 131 ProtectRange(HiAppMemEnd(), user_addr_max_l4); 132 // Older s390x kernels may not support 5-level page tables. 133 TryProtectRange(user_addr_max_l4, user_addr_max_l5); 134 #endif 135 } 136 #endif 137 138 } // namespace __tsan 139 140 #endif // SANITIZER_POSIX 141