xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
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 
noop()23 static void noop() {}
24 extern const char *argv0;
25 
26 namespace __sanitizer {
27 
28 #if SANITIZER_LINUX && !SANITIZER_ANDROID
TEST(MemoryMappingLayout,CodeRange)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 
TEST(MemoryMappingLayout,DumpListOfModules)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 
TEST(MemoryMapping,LoadedModuleArchAndUUID)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 
TEST(MemoryMapping,ParseUnixMemoryProfile)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 
TEST(MemoryMapping,ParseUnixMemoryProfileTruncated)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