xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- sanitizer_procmaps_test.cpp ---------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick #if !defined(_WIN32)  // There are no /proc/maps on Windows.
133cab2bb3Spatrick 
143cab2bb3Spatrick #  include "sanitizer_common/sanitizer_procmaps.h"
153cab2bb3Spatrick 
163cab2bb3Spatrick #  include <stdlib.h>
17*810390e3Srobert #  include <string.h>
18*810390e3Srobert 
19*810390e3Srobert #  include <vector>
20*810390e3Srobert 
21*810390e3Srobert #  include "gtest/gtest.h"
223cab2bb3Spatrick 
noop()233cab2bb3Spatrick static void noop() {}
243cab2bb3Spatrick extern const char *argv0;
253cab2bb3Spatrick 
263cab2bb3Spatrick namespace __sanitizer {
273cab2bb3Spatrick 
283cab2bb3Spatrick #if SANITIZER_LINUX && !SANITIZER_ANDROID
TEST(MemoryMappingLayout,CodeRange)293cab2bb3Spatrick TEST(MemoryMappingLayout, CodeRange) {
303cab2bb3Spatrick   uptr start, end;
313cab2bb3Spatrick   bool res = GetCodeRangeForFile("[vdso]", &start, &end);
323cab2bb3Spatrick   EXPECT_EQ(res, true);
333cab2bb3Spatrick   EXPECT_GT(start, 0U);
343cab2bb3Spatrick   EXPECT_LT(start, end);
353cab2bb3Spatrick }
363cab2bb3Spatrick #endif
373cab2bb3Spatrick 
TEST(MemoryMappingLayout,DumpListOfModules)383cab2bb3Spatrick TEST(MemoryMappingLayout, DumpListOfModules) {
393cab2bb3Spatrick   const char *last_slash = strrchr(argv0, '/');
403cab2bb3Spatrick   const char *binary_name = last_slash ? last_slash + 1 : argv0;
413cab2bb3Spatrick   MemoryMappingLayout memory_mapping(false);
423cab2bb3Spatrick   const uptr kMaxModules = 100;
433cab2bb3Spatrick   InternalMmapVector<LoadedModule> modules;
443cab2bb3Spatrick   modules.reserve(kMaxModules);
453cab2bb3Spatrick   memory_mapping.DumpListOfModules(&modules);
463cab2bb3Spatrick   EXPECT_GT(modules.size(), 0U);
473cab2bb3Spatrick   bool found = false;
483cab2bb3Spatrick   for (uptr i = 0; i < modules.size(); ++i) {
493cab2bb3Spatrick     if (modules[i].containsAddress((uptr)&noop)) {
503cab2bb3Spatrick       // Verify that the module name is sane.
513cab2bb3Spatrick       if (strstr(modules[i].full_name(), binary_name) != 0)
523cab2bb3Spatrick         found = true;
533cab2bb3Spatrick     }
543cab2bb3Spatrick     modules[i].clear();
553cab2bb3Spatrick   }
563cab2bb3Spatrick   EXPECT_TRUE(found);
573cab2bb3Spatrick }
583cab2bb3Spatrick 
TEST(MemoryMapping,LoadedModuleArchAndUUID)593cab2bb3Spatrick TEST(MemoryMapping, LoadedModuleArchAndUUID) {
60*810390e3Srobert   if (SANITIZER_APPLE) {
613cab2bb3Spatrick     MemoryMappingLayout memory_mapping(false);
623cab2bb3Spatrick     const uptr kMaxModules = 100;
633cab2bb3Spatrick     InternalMmapVector<LoadedModule> modules;
643cab2bb3Spatrick     modules.reserve(kMaxModules);
653cab2bb3Spatrick     memory_mapping.DumpListOfModules(&modules);
663cab2bb3Spatrick     for (uptr i = 0; i < modules.size(); ++i) {
673cab2bb3Spatrick       ModuleArch arch = modules[i].arch();
68*810390e3Srobert       // Darwin unit tests are only run on i386/x86_64/x86_64h/arm64.
693cab2bb3Spatrick       if (SANITIZER_WORDSIZE == 32) {
703cab2bb3Spatrick         EXPECT_EQ(arch, kModuleArchI386);
713cab2bb3Spatrick       } else if (SANITIZER_WORDSIZE == 64) {
72*810390e3Srobert         EXPECT_TRUE(arch == kModuleArchX86_64 || arch == kModuleArchX86_64H || arch == kModuleArchARM64);
733cab2bb3Spatrick       }
743cab2bb3Spatrick       const u8 *uuid = modules[i].uuid();
753cab2bb3Spatrick       u8 null_uuid[kModuleUUIDSize] = {0};
763cab2bb3Spatrick       EXPECT_NE(memcmp(null_uuid, uuid, kModuleUUIDSize), 0);
773cab2bb3Spatrick     }
783cab2bb3Spatrick   }
793cab2bb3Spatrick }
803cab2bb3Spatrick 
81*810390e3Srobert #  if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
82*810390e3Srobert        SANITIZER_SOLARIS) &&                                       \
83*810390e3Srobert       defined(_LP64)
84*810390e3Srobert const char *const parse_unix_input = R"(
85*810390e3Srobert 7fb9862f1000-7fb9862f3000 rw-p 00000000 00:00 0
86*810390e3Srobert Size:                  8 kB
87*810390e3Srobert Rss:                   4 kB
88*810390e3Srobert 7fb9864ae000-7fb9864b1000 r--p 001ba000 fd:01 22413919                   /lib/x86_64-linux-gnu/libc-2.32.so
89*810390e3Srobert Size:                 12 kB
90*810390e3Srobert Rss:                  12 kB
91*810390e3Srobert )";
92*810390e3Srobert 
TEST(MemoryMapping,ParseUnixMemoryProfile)93*810390e3Srobert TEST(MemoryMapping, ParseUnixMemoryProfile) {
94*810390e3Srobert   struct entry {
95*810390e3Srobert     uptr p;
96*810390e3Srobert     uptr rss;
97*810390e3Srobert     bool file;
98*810390e3Srobert   };
99*810390e3Srobert   typedef std::vector<entry> entries_t;
100*810390e3Srobert   entries_t entries;
101*810390e3Srobert   std::vector<char> input(parse_unix_input,
102*810390e3Srobert                           parse_unix_input + strlen(parse_unix_input));
103*810390e3Srobert   ParseUnixMemoryProfile(
104*810390e3Srobert       [](uptr p, uptr rss, bool file, uptr *mem) {
105*810390e3Srobert         reinterpret_cast<entries_t *>(mem)->push_back({p, rss, file});
106*810390e3Srobert       },
107*810390e3Srobert       reinterpret_cast<uptr *>(&entries), &input[0], input.size());
108*810390e3Srobert   EXPECT_EQ(entries.size(), 2ul);
109*810390e3Srobert   EXPECT_EQ(entries[0].p, 0x7fb9862f1000ul);
110*810390e3Srobert   EXPECT_EQ(entries[0].rss, 4ul << 10);
111*810390e3Srobert   EXPECT_EQ(entries[0].file, false);
112*810390e3Srobert   EXPECT_EQ(entries[1].p, 0x7fb9864ae000ul);
113*810390e3Srobert   EXPECT_EQ(entries[1].rss, 12ul << 10);
114*810390e3Srobert   EXPECT_EQ(entries[1].file, true);
115*810390e3Srobert }
116*810390e3Srobert 
TEST(MemoryMapping,ParseUnixMemoryProfileTruncated)117*810390e3Srobert TEST(MemoryMapping, ParseUnixMemoryProfileTruncated) {
118*810390e3Srobert   // ParseUnixMemoryProfile used to crash on truncated inputs.
119*810390e3Srobert   // This test allocates 2 pages, protects the second one
120*810390e3Srobert   // and places the input at the very end of the first page
121*810390e3Srobert   // to test for over-reads.
122*810390e3Srobert   uptr page = GetPageSizeCached();
123*810390e3Srobert   char *mem = static_cast<char *>(
124*810390e3Srobert       MmapOrDie(2 * page, "ParseUnixMemoryProfileTruncated"));
125*810390e3Srobert   EXPECT_TRUE(MprotectNoAccess(reinterpret_cast<uptr>(mem + page), page));
126*810390e3Srobert   const uptr len = strlen(parse_unix_input);
127*810390e3Srobert   for (uptr i = 0; i < len; i++) {
128*810390e3Srobert     char *smaps = mem + page - len + i;
129*810390e3Srobert     memcpy(smaps, parse_unix_input, len - i);
130*810390e3Srobert     ParseUnixMemoryProfile([](uptr p, uptr rss, bool file, uptr *mem) {},
131*810390e3Srobert                            nullptr, smaps, len - i);
132*810390e3Srobert   }
133*810390e3Srobert   UnmapOrDie(mem, 2 * page);
134*810390e3Srobert }
135*810390e3Srobert #  endif
136*810390e3Srobert 
1373cab2bb3Spatrick }  // namespace __sanitizer
1383cab2bb3Spatrick #endif  // !defined(_WIN32)
139