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 <android-base/test_utils.h>
18 #include <android-base/file.h>
19 #include <gtest/gtest.h>
20
21 #include "Memory.h"
22
23 class MemoryFileTest : public ::testing::Test {
24 protected:
SetUp()25 void SetUp() override {
26 tf_ = new TemporaryFile;
27 }
28
TearDown()29 void TearDown() override {
30 delete tf_;
31 }
32
WriteTestData()33 void WriteTestData() {
34 ASSERT_TRUE(android::base::WriteStringToFd("0123456789abcdefghijklmnopqrstuvxyz", tf_->fd));
35 }
36
37 MemoryFileAtOffset memory_;
38
39 TemporaryFile* tf_ = nullptr;
40 };
41
TEST_F(MemoryFileTest,offset_0)42 TEST_F(MemoryFileTest, offset_0) {
43 WriteTestData();
44
45 ASSERT_TRUE(memory_.Init(tf_->path, 0));
46 std::vector<char> buffer(11);
47 ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
48 buffer[10] = '\0';
49 ASSERT_STREQ("0123456789", buffer.data());
50 }
51
TEST_F(MemoryFileTest,offset_non_zero)52 TEST_F(MemoryFileTest, offset_non_zero) {
53 WriteTestData();
54
55 ASSERT_TRUE(memory_.Init(tf_->path, 10));
56 std::vector<char> buffer(11);
57 ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
58 buffer[10] = '\0';
59 ASSERT_STREQ("abcdefghij", buffer.data());
60 }
61
TEST_F(MemoryFileTest,offset_non_zero_larger_than_pagesize)62 TEST_F(MemoryFileTest, offset_non_zero_larger_than_pagesize) {
63 size_t pagesize = getpagesize();
64 std::string large_string;
65 for (size_t i = 0; i < pagesize; i++) {
66 large_string += '1';
67 }
68 large_string += "012345678901234abcdefgh";
69 ASSERT_TRUE(android::base::WriteStringToFd(large_string, tf_->fd));
70
71 ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
72 std::vector<char> buffer(9);
73 ASSERT_TRUE(memory_.Read(0, buffer.data(), 8));
74 buffer[8] = '\0';
75 ASSERT_STREQ("abcdefgh", buffer.data());
76 }
77
TEST_F(MemoryFileTest,offset_pagesize_aligned)78 TEST_F(MemoryFileTest, offset_pagesize_aligned) {
79 size_t pagesize = getpagesize();
80 std::string data;
81 for (size_t i = 0; i < 2 * pagesize; i++) {
82 data += static_cast<char>((i / pagesize) + '0');
83 data += static_cast<char>((i % 10) + '0');
84 }
85 ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
86
87 ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
88 std::vector<char> buffer(11);
89 ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
90 buffer[10] = '\0';
91 std::string expected_str;
92 for (size_t i = 0; i < 5; i++) {
93 expected_str += '1';
94 expected_str += static_cast<char>(((i + pagesize) % 10) + '0');
95 }
96 ASSERT_STREQ(expected_str.c_str(), buffer.data());
97 }
98
TEST_F(MemoryFileTest,offset_pagesize_aligned_plus_extra)99 TEST_F(MemoryFileTest, offset_pagesize_aligned_plus_extra) {
100 size_t pagesize = getpagesize();
101 std::string data;
102 for (size_t i = 0; i < 2 * pagesize; i++) {
103 data += static_cast<char>((i / pagesize) + '0');
104 data += static_cast<char>((i % 10) + '0');
105 }
106 ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
107
108 ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
109 std::vector<char> buffer(11);
110 ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
111 buffer[10] = '\0';
112 std::string expected_str;
113 for (size_t i = 0; i < 5; i++) {
114 expected_str += '1';
115 expected_str += static_cast<char>(((i + pagesize + 5) % 10) + '0');
116 }
117 ASSERT_STREQ(expected_str.c_str(), buffer.data());
118 }
119
TEST_F(MemoryFileTest,read_error)120 TEST_F(MemoryFileTest, read_error) {
121 std::string data;
122 for (size_t i = 0; i < 5000; i++) {
123 data += static_cast<char>((i % 10) + '0');
124 }
125 ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
126
127 std::vector<char> buffer(100);
128
129 // Read before init.
130 ASSERT_FALSE(memory_.Read(0, buffer.data(), 10));
131
132 ASSERT_TRUE(memory_.Init(tf_->path, 0));
133
134 ASSERT_FALSE(memory_.Read(10000, buffer.data(), 10));
135 ASSERT_FALSE(memory_.Read(5000, buffer.data(), 10));
136 ASSERT_FALSE(memory_.Read(4990, buffer.data(), 11));
137 ASSERT_TRUE(memory_.Read(4990, buffer.data(), 10));
138 ASSERT_FALSE(memory_.Read(4999, buffer.data(), 2));
139 ASSERT_TRUE(memory_.Read(4999, buffer.data(), 1));
140 }
141
TEST_F(MemoryFileTest,read_string)142 TEST_F(MemoryFileTest, read_string) {
143 std::string value("name_in_file");
144 ASSERT_TRUE(android::base::WriteFully(tf_->fd, value.c_str(), value.size() + 1));
145
146 std::string name;
147 ASSERT_TRUE(memory_.Init(tf_->path, 0));
148 ASSERT_TRUE(memory_.ReadString(0, &name));
149 ASSERT_EQ("name_in_file", name);
150 ASSERT_TRUE(memory_.ReadString(5, &name));
151 ASSERT_EQ("in_file", name);
152 }
153
TEST_F(MemoryFileTest,read_string_error)154 TEST_F(MemoryFileTest, read_string_error) {
155 std::vector<uint8_t> buffer = { 0x23, 0x32, 0x45 };
156 ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
157
158 std::string name;
159 ASSERT_TRUE(memory_.Init(tf_->path, 0));
160
161 // Read from a non-existant address.
162 ASSERT_FALSE(memory_.ReadString(100, &name));
163
164 // This should fail because there is no terminating \0
165 ASSERT_FALSE(memory_.ReadString(0, &name));
166 }
167
TEST_F(MemoryFileTest,read_past_file_within_mapping)168 TEST_F(MemoryFileTest, read_past_file_within_mapping) {
169 size_t pagesize = getpagesize();
170
171 ASSERT_TRUE(pagesize > 100);
172 std::vector<uint8_t> buffer(pagesize - 100);
173 for (size_t i = 0; i < pagesize - 100; i++) {
174 buffer[i] = static_cast<uint8_t>((i % 0x5e) + 0x20);
175 }
176 ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
177
178 ASSERT_TRUE(memory_.Init(tf_->path, 0));
179
180 for (size_t i = 0; i < 100; i++) {
181 uint8_t value;
182 ASSERT_FALSE(memory_.Read(buffer.size() + i, &value, 1)) << "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_.Read(pagesize * 2, read_buffer.data(), 1));
200 ASSERT_TRUE(memory_.Read(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_.Read(pagesize * 2, read_buffer.data(), 1));
224 ASSERT_TRUE(memory_.Read(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_.Read(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
250 ASSERT_TRUE(memory_.Read(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_.Read(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_.Read(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