1 /*
2  * Copyright (C) 2016 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 <string>
18 #include <vector>
19 
20 #include <android-base/test_utils.h>
21 #include <android-base/file.h>
22 #include <gtest/gtest.h>
23 
24 #include "MemoryFileAtOffset.h"
25 
26 namespace unwindstack {
27 
28 class MemoryFileTest : public ::testing::Test {
29  protected:
SetUp()30   void SetUp() override {
31     tf_ = new TemporaryFile;
32   }
33 
TearDown()34   void TearDown() override {
35     delete tf_;
36   }
37 
WriteTestData()38   void WriteTestData() {
39     ASSERT_TRUE(android::base::WriteStringToFd("0123456789abcdefghijklmnopqrstuvxyz", tf_->fd));
40   }
41 
42   MemoryFileAtOffset memory_;
43 
44   TemporaryFile* tf_ = nullptr;
45 };
46 
TEST_F(MemoryFileTest,init_offset_0)47 TEST_F(MemoryFileTest, init_offset_0) {
48   WriteTestData();
49 
50   ASSERT_TRUE(memory_.Init(tf_->path, 0));
51   std::vector<char> buffer(11);
52   ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
53   buffer[10] = '\0';
54   ASSERT_STREQ("0123456789", buffer.data());
55 }
56 
TEST_F(MemoryFileTest,init_offset_non_zero)57 TEST_F(MemoryFileTest, init_offset_non_zero) {
58   WriteTestData();
59 
60   ASSERT_TRUE(memory_.Init(tf_->path, 10));
61   std::vector<char> buffer(11);
62   ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
63   buffer[10] = '\0';
64   ASSERT_STREQ("abcdefghij", buffer.data());
65 }
66 
TEST_F(MemoryFileTest,init_offset_non_zero_larger_than_pagesize)67 TEST_F(MemoryFileTest, init_offset_non_zero_larger_than_pagesize) {
68   size_t pagesize = getpagesize();
69   std::string large_string;
70   for (size_t i = 0; i < pagesize; i++) {
71     large_string += '1';
72   }
73   large_string += "012345678901234abcdefgh";
74   ASSERT_TRUE(android::base::WriteStringToFd(large_string, tf_->fd));
75 
76   ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
77   std::vector<char> buffer(9);
78   ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 8));
79   buffer[8] = '\0';
80   ASSERT_STREQ("abcdefgh", buffer.data());
81 }
82 
TEST_F(MemoryFileTest,init_offset_pagesize_aligned)83 TEST_F(MemoryFileTest, init_offset_pagesize_aligned) {
84   size_t pagesize = getpagesize();
85   std::string data;
86   for (size_t i = 0; i < 2 * pagesize; i++) {
87     data += static_cast<char>((i / pagesize) + '0');
88     data += static_cast<char>((i % 10) + '0');
89   }
90   ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
91 
92   ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
93   std::vector<char> buffer(11);
94   ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
95   buffer[10] = '\0';
96   std::string expected_str;
97   for (size_t i = 0; i < 5; i++) {
98     expected_str += '1';
99     expected_str += static_cast<char>(((i + pagesize) % 10) + '0');
100   }
101   ASSERT_STREQ(expected_str.c_str(), buffer.data());
102 }
103 
TEST_F(MemoryFileTest,init_offset_pagesize_aligned_plus_extra)104 TEST_F(MemoryFileTest, init_offset_pagesize_aligned_plus_extra) {
105   size_t pagesize = getpagesize();
106   std::string data;
107   for (size_t i = 0; i < 2 * pagesize; i++) {
108     data += static_cast<char>((i / pagesize) + '0');
109     data += static_cast<char>((i % 10) + '0');
110   }
111   ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
112 
113   ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
114   std::vector<char> buffer(11);
115   ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
116   buffer[10] = '\0';
117   std::string expected_str;
118   for (size_t i = 0; i < 5; i++) {
119     expected_str += '1';
120     expected_str += static_cast<char>(((i + pagesize + 5) % 10) + '0');
121   }
122   ASSERT_STREQ(expected_str.c_str(), buffer.data());
123 }
124 
TEST_F(MemoryFileTest,init_offset_greater_than_filesize)125 TEST_F(MemoryFileTest, init_offset_greater_than_filesize) {
126   size_t pagesize = getpagesize();
127   std::string data;
128   uint64_t file_size = 2 * pagesize + pagesize / 2;
129   for (size_t i = 0; i < file_size; i++) {
130     data += static_cast<char>((i / pagesize) + '0');
131   }
132   ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
133 
134   // Check offset > file size fails and aligned_offset > file size.
135   ASSERT_FALSE(memory_.Init(tf_->path, file_size + 2 * pagesize));
136   // Check offset == filesize fails.
137   ASSERT_FALSE(memory_.Init(tf_->path, file_size));
138   // Check aligned_offset < filesize, but offset > filesize fails.
139   ASSERT_FALSE(memory_.Init(tf_->path, 2 * pagesize + pagesize / 2 + pagesize / 4));
140 }
141 
TEST_F(MemoryFileTest,read_error)142 TEST_F(MemoryFileTest, read_error) {
143   std::string data;
144   for (size_t i = 0; i < 5000; i++) {
145     data += static_cast<char>((i % 10) + '0');
146   }
147   ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
148 
149   std::vector<char> buffer(100);
150 
151   // Read before init.
152   ASSERT_FALSE(memory_.ReadFully(0, buffer.data(), 10));
153 
154   ASSERT_TRUE(memory_.Init(tf_->path, 0));
155 
156   ASSERT_FALSE(memory_.ReadFully(10000, buffer.data(), 10));
157   ASSERT_FALSE(memory_.ReadFully(5000, buffer.data(), 10));
158   ASSERT_FALSE(memory_.ReadFully(4990, buffer.data(), 11));
159   ASSERT_TRUE(memory_.ReadFully(4990, buffer.data(), 10));
160   ASSERT_FALSE(memory_.ReadFully(4999, buffer.data(), 2));
161   ASSERT_TRUE(memory_.ReadFully(4999, buffer.data(), 1));
162 
163   // Check that overflow fails properly.
164   ASSERT_FALSE(memory_.ReadFully(UINT64_MAX - 100, buffer.data(), 200));
165 }
166 
TEST_F(MemoryFileTest,read_past_file_within_mapping)167 TEST_F(MemoryFileTest, read_past_file_within_mapping) {
168   size_t pagesize = getpagesize();
169 
170   ASSERT_TRUE(pagesize > 100);
171   std::vector<uint8_t> buffer(pagesize - 100);
172   for (size_t i = 0; i < pagesize - 100; i++) {
173     buffer[i] = static_cast<uint8_t>((i % 0x5e) + 0x20);
174   }
175   ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
176 
177   ASSERT_TRUE(memory_.Init(tf_->path, 0));
178 
179   for (size_t i = 0; i < 100; i++) {
180     uint8_t value;
181     ASSERT_FALSE(memory_.ReadFully(buffer.size() + i, &value, 1))
182         << "Should have failed at value " << i;
183   }
184 }
185 
TEST_F(MemoryFileTest,map_partial_offset_aligned)186 TEST_F(MemoryFileTest, map_partial_offset_aligned) {
187   size_t pagesize = getpagesize();
188   std::vector<uint8_t> buffer(pagesize * 10);
189   for (size_t i = 0; i < pagesize * 10; i++) {
190     buffer[i] = i / pagesize + 1;
191   }
192   ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
193 
194   // Map in only two pages of the data, and after the first page.
195   ASSERT_TRUE(memory_.Init(tf_->path, pagesize, pagesize * 2));
196 
197   std::vector<uint8_t> read_buffer(pagesize * 2);
198   // Make sure that reading after mapped data is a failure.
199   ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
200   ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
201   for (size_t i = 0; i < pagesize; i++) {
202     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
203   }
204   for (size_t i = pagesize; i < pagesize * 2; i++) {
205     ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
206   }
207 }
208 
TEST_F(MemoryFileTest,map_partial_offset_unaligned)209 TEST_F(MemoryFileTest, map_partial_offset_unaligned) {
210   size_t pagesize = getpagesize();
211   ASSERT_TRUE(pagesize > 0x100);
212   std::vector<uint8_t> buffer(pagesize * 10);
213   for (size_t i = 0; i < buffer.size(); i++) {
214     buffer[i] = i / pagesize + 1;
215   }
216   ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
217 
218   // Map in only two pages of the data, and after the first page.
219   ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, pagesize * 2));
220 
221   std::vector<uint8_t> read_buffer(pagesize * 2);
222   // Make sure that reading after mapped data is a failure.
223   ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
224   ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
225   for (size_t i = 0; i < pagesize - 0x100; i++) {
226     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
227   }
228   for (size_t i = pagesize - 0x100; i < 2 * pagesize - 0x100; i++) {
229     ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
230   }
231   for (size_t i = 2 * pagesize - 0x100; i < pagesize * 2; i++) {
232     ASSERT_EQ(4, read_buffer[i]) << "Failed at byte " << i;
233   }
234 }
235 
TEST_F(MemoryFileTest,map_overflow)236 TEST_F(MemoryFileTest, map_overflow) {
237   size_t pagesize = getpagesize();
238   ASSERT_TRUE(pagesize > 0x100);
239   std::vector<uint8_t> buffer(pagesize * 10);
240   for (size_t i = 0; i < buffer.size(); i++) {
241     buffer[i] = i / pagesize + 1;
242   }
243   ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
244 
245   // Map in only two pages of the data, and after the first page.
246   ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, UINT64_MAX));
247 
248   std::vector<uint8_t> read_buffer(pagesize * 10);
249   ASSERT_FALSE(memory_.ReadFully(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
250   ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 9 - 0x100));
251 }
252 
TEST_F(MemoryFileTest,init_reinit)253 TEST_F(MemoryFileTest, init_reinit) {
254   size_t pagesize = getpagesize();
255   std::vector<uint8_t> buffer(pagesize * 2);
256   for (size_t i = 0; i < buffer.size(); i++) {
257     buffer[i] = i / pagesize + 1;
258   }
259   ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
260 
261   ASSERT_TRUE(memory_.Init(tf_->path, 0));
262   std::vector<uint8_t> read_buffer(buffer.size());
263   ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
264   for (size_t i = 0; i < pagesize; i++) {
265     ASSERT_EQ(1, read_buffer[i]) << "Failed at byte " << i;
266   }
267 
268   // Now reinit.
269   ASSERT_TRUE(memory_.Init(tf_->path, pagesize));
270   ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
271   for (size_t i = 0; i < pagesize; i++) {
272     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
273   }
274 }
275 
276 }  // namespace unwindstack
277