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: 30 void SetUp() override { 31 tf_ = new TemporaryFile; 32 } 33 34 void TearDown() override { 35 delete tf_; 36 } 37 38 void WriteTestData() { 39 ASSERT_TRUE(android::base::WriteStringToFd("0123456789abcdefghijklmnopqrstuvxyz", tf_->fd)); 40 } 41 42 MemoryFileAtOffset memory_; 43 44 TemporaryFile* tf_ = nullptr; 45 }; 46 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 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 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 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 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 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 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 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 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 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 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 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