1 /* 2 * Copyright (C) 2014 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 <gtest/gtest.h> 18 19 #include <sys/mman.h> 20 #include <sys/user.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include "TemporaryFile.h" 25 26 TEST(sys_mman, mmap_std) { 27 void* map = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 28 ASSERT_NE(MAP_FAILED, map); 29 ASSERT_EQ(0, munmap(map, 4096)); 30 } 31 32 TEST(sys_mman, mmap64_std) { 33 void* map = mmap64(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 34 ASSERT_NE(MAP_FAILED, map); 35 ASSERT_EQ(0, munmap(map, 4096)); 36 } 37 38 TEST(sys_mman, mmap_file_bad_offset) { 39 TemporaryFile tf; 40 41 void* map = mmap(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1); 42 ASSERT_EQ(MAP_FAILED, map); 43 } 44 45 TEST(sys_mman, mmap64_file_bad_offset) { 46 TemporaryFile tf; 47 48 void* map = mmap64(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1); 49 ASSERT_EQ(MAP_FAILED, map); 50 } 51 52 #define STR_SSIZE(str) static_cast<ssize_t>(sizeof(str)) 53 54 #define STRING_MSG "012345678\nabcdefgh\n" 55 #define INITIAL_MSG "000000000\n00000000\n" 56 57 TEST(sys_mman, mmap_file_read) { 58 TemporaryFile tf; 59 60 ASSERT_EQ(STR_SSIZE(STRING_MSG), write(tf.fd, STRING_MSG, sizeof(STRING_MSG))); 61 62 void* map = mmap(NULL, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0); 63 ASSERT_NE(MAP_FAILED, map); 64 65 char* data = reinterpret_cast<char*>(map); 66 ASSERT_STREQ(STRING_MSG, data); 67 68 ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG))); 69 } 70 71 TEST(sys_mman, mmap_file_write) { 72 TemporaryFile tf; 73 74 ASSERT_EQ(STR_SSIZE(INITIAL_MSG), write(tf.fd, INITIAL_MSG, sizeof(INITIAL_MSG))); 75 lseek(tf.fd, 0, SEEK_SET); 76 77 void* map = mmap(NULL, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0); 78 ASSERT_NE(MAP_FAILED, map); 79 close(tf.fd); 80 81 memcpy(map, STRING_MSG, sizeof(STRING_MSG)); 82 83 ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG))); 84 85 tf.reopen(); 86 char buf[sizeof(STRING_MSG)]; 87 memset(buf, 0, sizeof(STRING_MSG)); 88 ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG))); 89 90 ASSERT_STREQ(STRING_MSG, buf); 91 } 92 93 #define PAGE0_MSG "00PAGE00" 94 #define PAGE1_MSG "111PAGE111" 95 #define PAGE2_MSG "2222PAGE2222" 96 #define END_MSG "E" 97 98 TEST(sys_mman, mmap_file_read_at_offset) { 99 TemporaryFile tf; 100 size_t pagesize = sysconf(_SC_PAGESIZE); 101 102 // Create the file with three pages worth of data. 103 ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG))); 104 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET)); 105 ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG))); 106 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET)); 107 ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG))); 108 ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET)); 109 ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG))); 110 111 ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET)); 112 113 void* map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize); 114 ASSERT_NE(MAP_FAILED, map); 115 116 char* data = reinterpret_cast<char*>(map); 117 ASSERT_STREQ(PAGE1_MSG, data); 118 119 ASSERT_EQ(0, munmap(map, pagesize)); 120 121 map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize); 122 ASSERT_NE(MAP_FAILED, map); 123 124 data = reinterpret_cast<char*>(map); 125 ASSERT_STREQ(PAGE2_MSG, data); 126 ASSERT_STREQ(END_MSG, data+pagesize-sizeof(END_MSG)); 127 128 ASSERT_EQ(0, munmap(map, pagesize)); 129 } 130 131 #define NEWPAGE1_MSG "1NEW1PAGE1" 132 #define NEWPAGE2_MSG "22NEW22PAGE22" 133 134 TEST(sys_mman, mmap_file_write_at_offset) { 135 TemporaryFile tf; 136 size_t pagesize = sysconf(_SC_PAGESIZE); 137 138 // Create the file with three pages worth of data. 139 ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG))); 140 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET)); 141 ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG))); 142 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET)); 143 ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG))); 144 ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET)); 145 ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG))); 146 147 ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET)); 148 149 void* map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize); 150 ASSERT_NE(MAP_FAILED, map); 151 close(tf.fd); 152 153 memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG)); 154 ASSERT_EQ(0, munmap(map, pagesize)); 155 156 tf.reopen(); 157 map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize); 158 ASSERT_NE(MAP_FAILED, map); 159 close(tf.fd); 160 161 memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG)); 162 ASSERT_EQ(0, munmap(map, pagesize)); 163 164 tf.reopen(); 165 char buf[pagesize]; 166 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize)); 167 ASSERT_STREQ(PAGE0_MSG, buf); 168 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET)); 169 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize)); 170 ASSERT_STREQ(NEWPAGE1_MSG, buf); 171 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET)); 172 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize)); 173 ASSERT_STREQ(NEWPAGE2_MSG, buf); 174 ASSERT_STREQ(END_MSG, buf+pagesize-sizeof(END_MSG)); 175 } 176 177 TEST(sys_mman, posix_madvise) { 178 TemporaryFile tempfile; 179 size_t pagesize = sysconf(_SC_PAGESIZE); 180 char buf[pagesize]; 181 182 // Prepare environment. 183 ASSERT_EQ(static_cast<ssize_t>(pagesize), write(tempfile.fd, buf, pagesize)); 184 void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0); 185 ASSERT_NE(MAP_FAILED, map); 186 187 // Verify different options of posix_madvise. 188 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_NORMAL)); 189 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_SEQUENTIAL)); 190 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_RANDOM)); 191 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_WILLNEED)); 192 193 ASSERT_EQ(0, munmap(map, pagesize)); 194 } 195 196 // Verify that memory can still access after posix_madvise(POSIX_MADV_DONTNEED). 197 // We should test on MAP_ANONYMOUS memory to verify whether the memory is discarded, 198 // because the content of non MAP_ANONYMOUS memory can be reread from file. 199 TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) { 200 size_t pagesize = sysconf(_SC_PAGESIZE); 201 202 void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 203 ASSERT_NE(MAP_FAILED, map); 204 205 int* int_ptr = reinterpret_cast<int*>(map); 206 for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) { 207 *int_ptr++ = i; 208 } 209 210 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_DONTNEED)); 211 212 int_ptr = reinterpret_cast<int*>(map); 213 for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) { 214 ASSERT_EQ(i, *int_ptr++); 215 } 216 217 ASSERT_EQ(0, munmap(map, pagesize)); 218 } 219 220 TEST(sys_mman, mremap) { 221 ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0)); 222 } 223 224 constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1; 225 226 TEST(sys_mman, mmap_PTRDIFF_MAX) { 227 ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); 228 } 229 230 TEST(sys_mman, mremap_PTRDIFF_MAX) { 231 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 232 ASSERT_NE(MAP_FAILED, map); 233 ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE)); 234 } 235 236 TEST(sys_mman, mmap_bug_27265969) { 237 char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ, 238 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 239 // Some kernels had bugs that would cause segfaults here... 240 __builtin___clear_cache(base, base + (PAGE_SIZE * 2)); 241 } 242