1 // Copyright 2011 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // memory_mapped_file_unittest.cc:
30 // Unit tests for google_breakpad::MemoryMappedFile.
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h> // Must come first
34 #endif
35
36 #include <fcntl.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include <string>
41
42 #include "breakpad_googletest_includes.h"
43 #include "common/linux/memory_mapped_file.h"
44 #include "common/tests/auto_tempdir.h"
45 #include "common/tests/file_utils.h"
46 #include "common/using_std_string.h"
47
48 using google_breakpad::AutoTempDir;
49 using google_breakpad::MemoryMappedFile;
50 using google_breakpad::WriteFile;
51
52 namespace {
53
54 class MemoryMappedFileTest : public testing::Test {
55 protected:
ExpectNoMappedData(const MemoryMappedFile & mapped_file)56 void ExpectNoMappedData(const MemoryMappedFile& mapped_file) {
57 EXPECT_TRUE(mapped_file.content().IsEmpty());
58 EXPECT_TRUE(mapped_file.data() == NULL);
59 EXPECT_EQ(0U, mapped_file.size());
60 }
61 };
62
63 } // namespace
64
TEST_F(MemoryMappedFileTest,DefaultConstructor)65 TEST_F(MemoryMappedFileTest, DefaultConstructor) {
66 MemoryMappedFile mapped_file;
67 ExpectNoMappedData(mapped_file);
68 }
69
TEST_F(MemoryMappedFileTest,UnmapWithoutMap)70 TEST_F(MemoryMappedFileTest, UnmapWithoutMap) {
71 MemoryMappedFile mapped_file;
72 mapped_file.Unmap();
73 }
74
TEST_F(MemoryMappedFileTest,MapNonexistentFile)75 TEST_F(MemoryMappedFileTest, MapNonexistentFile) {
76 {
77 MemoryMappedFile mapped_file("nonexistent-file", 0);
78 ExpectNoMappedData(mapped_file);
79 }
80 {
81 MemoryMappedFile mapped_file;
82 EXPECT_FALSE(mapped_file.Map("nonexistent-file", 0));
83 ExpectNoMappedData(mapped_file);
84 }
85 }
86
TEST_F(MemoryMappedFileTest,MapEmptyFile)87 TEST_F(MemoryMappedFileTest, MapEmptyFile) {
88 AutoTempDir temp_dir;
89 string test_file = temp_dir.path() + "/empty_file";
90 ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0));
91
92 {
93 MemoryMappedFile mapped_file(test_file.c_str(), 0);
94 ExpectNoMappedData(mapped_file);
95 }
96 {
97 MemoryMappedFile mapped_file;
98 EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
99 ExpectNoMappedData(mapped_file);
100 }
101 }
102
TEST_F(MemoryMappedFileTest,MapNonEmptyFile)103 TEST_F(MemoryMappedFileTest, MapNonEmptyFile) {
104 char data[256];
105 size_t data_size = sizeof(data);
106 for (size_t i = 0; i < data_size; ++i) {
107 data[i] = i;
108 }
109
110 AutoTempDir temp_dir;
111 string test_file = temp_dir.path() + "/test_file";
112 ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size));
113
114 {
115 MemoryMappedFile mapped_file(test_file.c_str(), 0);
116 EXPECT_FALSE(mapped_file.content().IsEmpty());
117 EXPECT_TRUE(mapped_file.data() != NULL);
118 EXPECT_EQ(data_size, mapped_file.size());
119 EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
120 }
121 {
122 MemoryMappedFile mapped_file;
123 EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
124 EXPECT_FALSE(mapped_file.content().IsEmpty());
125 EXPECT_TRUE(mapped_file.data() != NULL);
126 EXPECT_EQ(data_size, mapped_file.size());
127 EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
128 }
129 }
130
TEST_F(MemoryMappedFileTest,RemapAfterMap)131 TEST_F(MemoryMappedFileTest, RemapAfterMap) {
132 char data1[256];
133 size_t data1_size = sizeof(data1);
134 for (size_t i = 0; i < data1_size; ++i) {
135 data1[i] = i;
136 }
137
138 char data2[50];
139 size_t data2_size = sizeof(data2);
140 for (size_t i = 0; i < data2_size; ++i) {
141 data2[i] = 255 - i;
142 }
143
144 AutoTempDir temp_dir;
145 string test_file1 = temp_dir.path() + "/test_file1";
146 string test_file2 = temp_dir.path() + "/test_file2";
147 ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
148 ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size));
149
150 {
151 MemoryMappedFile mapped_file(test_file1.c_str(), 0);
152 EXPECT_FALSE(mapped_file.content().IsEmpty());
153 EXPECT_TRUE(mapped_file.data() != NULL);
154 EXPECT_EQ(data1_size, mapped_file.size());
155 EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
156
157 mapped_file.Map(test_file2.c_str(), 0);
158 EXPECT_FALSE(mapped_file.content().IsEmpty());
159 EXPECT_TRUE(mapped_file.data() != NULL);
160 EXPECT_EQ(data2_size, mapped_file.size());
161 EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
162 }
163 {
164 MemoryMappedFile mapped_file;
165 EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0));
166 EXPECT_FALSE(mapped_file.content().IsEmpty());
167 EXPECT_TRUE(mapped_file.data() != NULL);
168 EXPECT_EQ(data1_size, mapped_file.size());
169 EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
170
171 mapped_file.Map(test_file2.c_str(), 0);
172 EXPECT_FALSE(mapped_file.content().IsEmpty());
173 EXPECT_TRUE(mapped_file.data() != NULL);
174 EXPECT_EQ(data2_size, mapped_file.size());
175 EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
176 }
177 }
178
TEST_F(MemoryMappedFileTest,MapWithOffset)179 TEST_F(MemoryMappedFileTest, MapWithOffset) {
180 // Put more data in the test file this time. Offsets can only be
181 // done on page boundaries, so we need a two page file to test this.
182 const int page_size = 4096;
183 char data1[2 * page_size];
184 size_t data1_size = sizeof(data1);
185 for (size_t i = 0; i < data1_size; ++i) {
186 data1[i] = i & 0x7f;
187 }
188
189 AutoTempDir temp_dir;
190 string test_file1 = temp_dir.path() + "/test_file1";
191 ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
192 {
193 MemoryMappedFile mapped_file(test_file1.c_str(), page_size);
194 EXPECT_FALSE(mapped_file.content().IsEmpty());
195 EXPECT_TRUE(mapped_file.data() != NULL);
196 EXPECT_EQ(data1_size - page_size, mapped_file.size());
197 EXPECT_EQ(
198 0,
199 memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
200 }
201 {
202 MemoryMappedFile mapped_file;
203 mapped_file.Map(test_file1.c_str(), page_size);
204 EXPECT_FALSE(mapped_file.content().IsEmpty());
205 EXPECT_TRUE(mapped_file.data() != NULL);
206 EXPECT_EQ(data1_size - page_size, mapped_file.size());
207 EXPECT_EQ(
208 0,
209 memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
210 }
211 }
212