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