127 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- tsan_platform_posix.cpp -------------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file is a part of ThreadSanitizer (TSan), a race detector.
 | |
| //
 | |
| // POSIX-specific code.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "sanitizer_common/sanitizer_platform.h"
 | |
| #if SANITIZER_POSIX
 | |
| 
 | |
| #include "sanitizer_common/sanitizer_common.h"
 | |
| #include "sanitizer_common/sanitizer_errno.h"
 | |
| #include "sanitizer_common/sanitizer_libc.h"
 | |
| #include "sanitizer_common/sanitizer_procmaps.h"
 | |
| #include "tsan_platform.h"
 | |
| #include "tsan_rtl.h"
 | |
| 
 | |
| namespace __tsan {
 | |
| 
 | |
| static const char kShadowMemoryMappingWarning[] =
 | |
|     "FATAL: %s can not madvise shadow region [%zx, %zx] with %s (errno: %d)\n";
 | |
| static const char kShadowMemoryMappingHint[] =
 | |
|     "HINT: if %s is not supported in your environment, you may set "
 | |
|     "TSAN_OPTIONS=%s=0\n";
 | |
| 
 | |
| static void DontDumpShadow(uptr addr, uptr size) {
 | |
|   if (common_flags()->use_madv_dontdump)
 | |
|     if (!DontDumpShadowMemory(addr, size)) {
 | |
|       Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size,
 | |
|              "MADV_DONTDUMP", errno);
 | |
|       Printf(kShadowMemoryMappingHint, "MADV_DONTDUMP", "use_madv_dontdump");
 | |
|       Die();
 | |
|     }
 | |
| }
 | |
| 
 | |
| #if !SANITIZER_GO
 | |
| void InitializeShadowMemory() {
 | |
|   // Map memory shadow.
 | |
|   if (!MmapFixedSuperNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(),
 | |
|                                "shadow")) {
 | |
|     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
 | |
|     Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
 | |
|     Die();
 | |
|   }
 | |
|   // This memory range is used for thread stacks and large user mmaps.
 | |
|   // Frequently a thread uses only a small part of stack and similarly
 | |
|   // a program uses a small part of large mmap. On some programs
 | |
|   // we see 20% memory usage reduction without huge pages for this range.
 | |
|   DontDumpShadow(ShadowBeg(), ShadowEnd() - ShadowBeg());
 | |
|   DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
 | |
|       ShadowBeg(), ShadowEnd(),
 | |
|       (ShadowEnd() - ShadowBeg()) >> 30);
 | |
| 
 | |
|   // Map meta shadow.
 | |
|   const uptr meta = MetaShadowBeg();
 | |
|   const uptr meta_size = MetaShadowEnd() - meta;
 | |
|   if (!MmapFixedSuperNoReserve(meta, meta_size, "meta shadow")) {
 | |
|     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
 | |
|     Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
 | |
|     Die();
 | |
|   }
 | |
|   DontDumpShadow(meta, meta_size);
 | |
|   DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
 | |
|       meta, meta + meta_size, meta_size >> 30);
 | |
| 
 | |
|   InitializeShadowMemoryPlatform();
 | |
| }
 | |
| 
 | |
| static void ProtectRange(uptr beg, uptr end) {
 | |
|   CHECK_LE(beg, end);
 | |
|   if (beg == end)
 | |
|     return;
 | |
|   if (beg != (uptr)MmapFixedNoAccess(beg, end - beg)) {
 | |
|     Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
 | |
|     Printf("FATAL: Make sure you are not using unlimited stack\n");
 | |
|     Die();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CheckAndProtect() {
 | |
|   // Ensure that the binary is indeed compiled with -pie.
 | |
|   MemoryMappingLayout proc_maps(true);
 | |
|   MemoryMappedSegment segment;
 | |
|   while (proc_maps.Next(&segment)) {
 | |
|     if (IsAppMem(segment.start)) continue;
 | |
|     if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue;
 | |
|     if (segment.protection == 0)  // Zero page or mprotected.
 | |
|       continue;
 | |
|     if (segment.start >= VdsoBeg())  // vdso
 | |
|       break;
 | |
|     Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n",
 | |
|            segment.start, segment.end);
 | |
|     Die();
 | |
|   }
 | |
| 
 | |
| #if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
 | |
|   ProtectRange(HeapMemEnd(), ShadowBeg());
 | |
|   ProtectRange(ShadowEnd(), MetaShadowBeg());
 | |
|   ProtectRange(MetaShadowEnd(), TraceMemBeg());
 | |
| #else
 | |
|   ProtectRange(LoAppMemEnd(), ShadowBeg());
 | |
|   ProtectRange(ShadowEnd(), MetaShadowBeg());
 | |
| #ifdef TSAN_MID_APP_RANGE
 | |
|   ProtectRange(MetaShadowEnd(), MidAppMemBeg());
 | |
|   ProtectRange(MidAppMemEnd(), TraceMemBeg());
 | |
| #else
 | |
|   ProtectRange(MetaShadowEnd(), TraceMemBeg());
 | |
| #endif
 | |
|   // Memory for traces is mapped lazily in MapThreadTrace.
 | |
|   // Protect the whole range for now, so that user does not map something here.
 | |
|   ProtectRange(TraceMemBeg(), TraceMemEnd());
 | |
|   ProtectRange(TraceMemEnd(), HeapMemBeg());
 | |
|   ProtectRange(HeapEnd(), HiAppMemBeg());
 | |
| #endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| }  // namespace __tsan
 | |
| 
 | |
| #endif  // SANITIZER_POSIX
 |