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
23static void noop() {}
24extern const char *argv0;
25
26namespace __sanitizer {
27
28# if SANITIZER_LINUX && !SANITIZER_ANDROID
29TEST(MemoryMappingLayout, CodeRange) {
30 uptr start, end;
31 bool res = GetCodeRangeForFile(module: "[vdso]", start: &start, end: &end);
32 EXPECT_EQ(res, true);
33 EXPECT_GT(start, 0U);
34 EXPECT_LT(start, end);
35}
36# endif
37
38TEST(MemoryMappingLayout, DumpListOfModules) {
39 const char *last_slash = strrchr(s: argv0, c: '/');
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(new_size: kMaxModules);
45 memory_mapping.DumpListOfModules(modules: &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(address: (uptr)&noop)) {
50 // Verify that the module name is sane.
51 if (strstr(haystack: modules[i].full_name(), needle: binary_name) != 0)
52 found = true;
53 }
54 modules[i].clear();
55 }
56 EXPECT_TRUE(found);
57}
58
59TEST(MemoryMapping, LoadedModuleArchAndUUID) {
60 if (SANITIZER_APPLE) {
61 MemoryMappingLayout memory_mapping(false);
62 const uptr kMaxModules = 100;
63 InternalMmapVector<LoadedModule> modules;
64 modules.reserve(new_size: kMaxModules);
65 memory_mapping.DumpListOfModules(modules: &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 ||
73 arch == kModuleArchARM64);
74 }
75 const u8 *uuid = modules[i].uuid();
76 u8 null_uuid[kModuleUUIDSize] = {0};
77 EXPECT_NE(memcmp(s1: null_uuid, s2: uuid, n: kModuleUUIDSize), 0);
78 }
79 }
80}
81
82# if (SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_SOLARIS) && \
83 defined(_LP64)
84const char *const parse_unix_input = R"(
857fb9862f1000-7fb9862f3000 rw-p 00000000 00:00 0
86Size: 8 kB
87Rss: 4 kB
887fb9864ae000-7fb9864b1000 r--p 001ba000 fd:01 22413919 /lib/x86_64-linux-gnu/libc-2.32.so
89Size: 12 kB
90Rss: 12 kB
91)";
92
93TEST(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
117TEST(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

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cpp