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 <unwindstack/Memory.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