1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/ext/base/scoped_mmap.h"
18
19 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
20 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
21 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
22 #include <sys/mman.h>
23 #include <unistd.h>
24 #endif
25
26 #include "perfetto/ext/base/file_utils.h"
27 #include "src/base/test/tmp_dir_tree.h"
28 #include "test/gtest_and_gmock.h"
29
30 namespace perfetto::base {
31 namespace {
32
33 class ScopedMmapTest : public ::testing::Test {
SetUp()34 void SetUp() override {
35 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) && \
36 !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
37 !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
38 !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
39 GTEST_SKIP() << "mmap not supported";
40 #endif
41 }
42 };
43
TEST_F(ScopedMmapTest,WholeNonExistingFile)44 TEST_F(ScopedMmapTest, WholeNonExistingFile) {
45 base::TmpDirTree tmp;
46
47 ScopedMmap mapped = ReadMmapWholeFile(tmp.AbsolutePath("f1.txt").c_str());
48
49 EXPECT_FALSE(mapped.IsValid());
50 }
51
TEST_F(ScopedMmapTest,PartNonExistingFile)52 TEST_F(ScopedMmapTest, PartNonExistingFile) {
53 base::TmpDirTree tmp;
54
55 ScopedMmap mapped = ReadMmapFilePart(tmp.AbsolutePath("f1.txt").c_str(), 4);
56
57 EXPECT_FALSE(mapped.IsValid());
58 }
59
TEST_F(ScopedMmapTest,WholeOneByteFile)60 TEST_F(ScopedMmapTest, WholeOneByteFile) {
61 base::TmpDirTree tmp;
62 tmp.AddFile("f1.txt", "c");
63
64 ScopedMmap mapped = ReadMmapWholeFile(tmp.AbsolutePath("f1.txt").c_str());
65
66 ASSERT_TRUE(mapped.IsValid());
67 ASSERT_NE(mapped.data(), nullptr);
68 ASSERT_EQ(mapped.length(), 1u);
69 EXPECT_EQ(*static_cast<char*>(mapped.data()), 'c');
70 }
71
TEST_F(ScopedMmapTest,PartThreeBytes)72 TEST_F(ScopedMmapTest, PartThreeBytes) {
73 base::TmpDirTree tmp;
74 tmp.AddFile("f1.txt", "ccccc");
75
76 ScopedMmap mapped = ReadMmapFilePart(tmp.AbsolutePath("f1.txt").c_str(), 3);
77
78 ASSERT_TRUE(mapped.IsValid());
79 ASSERT_NE(mapped.data(), nullptr);
80 ASSERT_EQ(mapped.length(), 3u);
81 }
82
TEST_F(ScopedMmapTest,Reset)83 TEST_F(ScopedMmapTest, Reset) {
84 base::TmpDirTree tmp;
85 tmp.AddFile("f1.txt", "ccccc");
86 ScopedMmap mapped = ReadMmapWholeFile(tmp.AbsolutePath("f1.txt").c_str());
87 ASSERT_TRUE(mapped.IsValid());
88
89 EXPECT_TRUE(mapped.reset());
90
91 EXPECT_FALSE(mapped.IsValid());
92 }
93
94 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
95 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
96 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
TEST_F(ScopedMmapTest,InheritMmappedRange)97 TEST_F(ScopedMmapTest, InheritMmappedRange) {
98 base::TmpDirTree tmp;
99 tmp.AddFile("f1.txt", "ccccc");
100 ScopedPlatformHandle file(
101 base::OpenFile(tmp.AbsolutePath("f1.txt").c_str(), O_RDONLY));
102 void* ptr = mmap(nullptr, 5, PROT_READ, MAP_PRIVATE, *file, 0);
103 ASSERT_NE(ptr, MAP_FAILED);
104
105 ScopedMmap mapped = ScopedMmap::InheritMmappedRange(ptr, 5);
106 file.reset();
107
108 ASSERT_TRUE(mapped.IsValid());
109 ASSERT_EQ(mapped.length(), 5u);
110 EXPECT_EQ(*static_cast<char*>(mapped.data()), 'c');
111 }
112 #endif
113
114 } // namespace
115 } // namespace perfetto::base
116