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