1 //===-- sanitizer_procmaps_test.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/AddressSanitizer runtime. 10 // 11 //===----------------------------------------------------------------------===// 12 #if !defined(_WIN32) // There are no /proc/maps on Windows. 13 14 # include "sanitizer_common/sanitizer_procmaps.h" 15 16 # include <stdlib.h> 17 # include <string.h> 18 19 # include <vector> 20 21 # include "gtest/gtest.h" 22 23 static void noop() {} 24 extern const char *argv0; 25 26 namespace __sanitizer { 27 28 #if SANITIZER_LINUX && !SANITIZER_ANDROID 29 TEST(MemoryMappingLayout, CodeRange) { 30 uptr start, end; 31 bool res = GetCodeRangeForFile("[vdso]", &start, &end); 32 EXPECT_EQ(res, true); 33 EXPECT_GT(start, 0U); 34 EXPECT_LT(start, end); 35 } 36 #endif 37 38 TEST(MemoryMappingLayout, DumpListOfModules) { 39 const char *last_slash = strrchr(argv0, '/'); 40 const char *binary_name = last_slash ? last_slash + 1 : argv0; 41 MemoryMappingLayout memory_mapping(false); 42 const uptr kMaxModules = 100; 43 InternalMmapVector<LoadedModule> modules; 44 modules.reserve(kMaxModules); 45 memory_mapping.DumpListOfModules(&modules); 46 EXPECT_GT(modules.size(), 0U); 47 bool found = false; 48 for (uptr i = 0; i < modules.size(); ++i) { 49 if (modules[i].containsAddress((uptr)&noop)) { 50 // Verify that the module name is sane. 51 if (strstr(modules[i].full_name(), binary_name) != 0) 52 found = true; 53 } 54 modules[i].clear(); 55 } 56 EXPECT_TRUE(found); 57 } 58 59 TEST(MemoryMapping, LoadedModuleArchAndUUID) { 60 if (SANITIZER_APPLE) { 61 MemoryMappingLayout memory_mapping(false); 62 const uptr kMaxModules = 100; 63 InternalMmapVector<LoadedModule> modules; 64 modules.reserve(kMaxModules); 65 memory_mapping.DumpListOfModules(&modules); 66 for (uptr i = 0; i < modules.size(); ++i) { 67 ModuleArch arch = modules[i].arch(); 68 // Darwin unit tests are only run on i386/x86_64/x86_64h/arm64. 69 if (SANITIZER_WORDSIZE == 32) { 70 EXPECT_EQ(arch, kModuleArchI386); 71 } else if (SANITIZER_WORDSIZE == 64) { 72 EXPECT_TRUE(arch == kModuleArchX86_64 || arch == kModuleArchX86_64H || arch == kModuleArchARM64); 73 } 74 const u8 *uuid = modules[i].uuid(); 75 u8 null_uuid[kModuleUUIDSize] = {0}; 76 EXPECT_NE(memcmp(null_uuid, uuid, kModuleUUIDSize), 0); 77 } 78 } 79 } 80 81 # if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 82 SANITIZER_SOLARIS) && \ 83 defined(_LP64) 84 const char *const parse_unix_input = R"( 85 7fb9862f1000-7fb9862f3000 rw-p 00000000 00:00 0 86 Size: 8 kB 87 Rss: 4 kB 88 7fb9864ae000-7fb9864b1000 r--p 001ba000 fd:01 22413919 /lib/x86_64-linux-gnu/libc-2.32.so 89 Size: 12 kB 90 Rss: 12 kB 91 )"; 92 93 TEST(MemoryMapping, ParseUnixMemoryProfile) { 94 struct entry { 95 uptr p; 96 uptr rss; 97 bool file; 98 }; 99 typedef std::vector<entry> entries_t; 100 entries_t entries; 101 std::vector<char> input(parse_unix_input, 102 parse_unix_input + strlen(parse_unix_input)); 103 ParseUnixMemoryProfile( 104 [](uptr p, uptr rss, bool file, uptr *mem) { 105 reinterpret_cast<entries_t *>(mem)->push_back({p, rss, file}); 106 }, 107 reinterpret_cast<uptr *>(&entries), &input[0], input.size()); 108 EXPECT_EQ(entries.size(), 2ul); 109 EXPECT_EQ(entries[0].p, 0x7fb9862f1000ul); 110 EXPECT_EQ(entries[0].rss, 4ul << 10); 111 EXPECT_EQ(entries[0].file, false); 112 EXPECT_EQ(entries[1].p, 0x7fb9864ae000ul); 113 EXPECT_EQ(entries[1].rss, 12ul << 10); 114 EXPECT_EQ(entries[1].file, true); 115 } 116 117 TEST(MemoryMapping, ParseUnixMemoryProfileTruncated) { 118 // ParseUnixMemoryProfile used to crash on truncated inputs. 119 // This test allocates 2 pages, protects the second one 120 // and places the input at the very end of the first page 121 // to test for over-reads. 122 uptr page = GetPageSizeCached(); 123 char *mem = static_cast<char *>( 124 MmapOrDie(2 * page, "ParseUnixMemoryProfileTruncated")); 125 EXPECT_TRUE(MprotectNoAccess(reinterpret_cast<uptr>(mem + page), page)); 126 const uptr len = strlen(parse_unix_input); 127 for (uptr i = 0; i < len; i++) { 128 char *smaps = mem + page - len + i; 129 memcpy(smaps, parse_unix_input, len - i); 130 ParseUnixMemoryProfile([](uptr p, uptr rss, bool file, uptr *mem) {}, 131 nullptr, smaps, len - i); 132 } 133 UnmapOrDie(mem, 2 * page); 134 } 135 # endif 136 137 } // namespace __sanitizer 138 #endif // !defined(_WIN32) 139