• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <fcntl.h>
18 #include <sys/mman.h>
19 #include <sys/user.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include <android-base/file.h>
24 #include <gtest/gtest.h>
25 
26 #include "utils.h"
27 
28 static const size_t kPageSize = getpagesize();
29 
TEST(sys_mman,mmap_std)30 TEST(sys_mman, mmap_std) {
31   void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
32   ASSERT_NE(MAP_FAILED, map);
33   ASSERT_EQ(0, munmap(map, 4096));
34 }
35 
TEST(sys_mman,mmap64_std)36 TEST(sys_mman, mmap64_std) {
37   void* map = mmap64(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
38   ASSERT_NE(MAP_FAILED, map);
39   ASSERT_EQ(0, munmap(map, 4096));
40 }
41 
TEST(sys_mman,mmap_file_bad_offset)42 TEST(sys_mman, mmap_file_bad_offset) {
43   TemporaryFile tf;
44 
45   void* map = mmap(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
46   ASSERT_EQ(MAP_FAILED, map);
47 }
48 
TEST(sys_mman,mmap64_file_bad_offset)49 TEST(sys_mman, mmap64_file_bad_offset) {
50   TemporaryFile tf;
51 
52   void* map = mmap64(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
53   ASSERT_EQ(MAP_FAILED, map);
54 }
55 
56 #define STR_SSIZE(str) static_cast<ssize_t>(sizeof(str))
57 
58 #define STRING_MSG  "012345678\nabcdefgh\n"
59 #define INITIAL_MSG "000000000\n00000000\n"
60 
TEST(sys_mman,mmap_file_read)61 TEST(sys_mman, mmap_file_read) {
62   TemporaryFile tf;
63 
64   ASSERT_EQ(STR_SSIZE(STRING_MSG), write(tf.fd, STRING_MSG, sizeof(STRING_MSG)));
65 
66   void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0);
67   ASSERT_NE(MAP_FAILED, map);
68 
69   char* data = reinterpret_cast<char*>(map);
70   ASSERT_STREQ(STRING_MSG, data);
71 
72   ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
73 }
74 
TEST(sys_mman,mmap_file_write)75 TEST(sys_mman, mmap_file_write) {
76   TemporaryFile tf;
77 
78   ASSERT_EQ(STR_SSIZE(INITIAL_MSG), write(tf.fd, INITIAL_MSG, sizeof(INITIAL_MSG)));
79   lseek(tf.fd, 0, SEEK_SET);
80 
81   void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0);
82   ASSERT_NE(MAP_FAILED, map);
83   close(tf.fd);
84 
85   memcpy(map, STRING_MSG, sizeof(STRING_MSG));
86 
87   ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
88 
89   tf.fd = open(tf.path, O_RDWR);
90   char buf[sizeof(STRING_MSG)];
91   memset(buf, 0, sizeof(STRING_MSG));
92   ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG)));
93 
94   ASSERT_STREQ(STRING_MSG, buf);
95 }
96 
97 #define PAGE0_MSG "00PAGE00"
98 #define PAGE1_MSG "111PAGE111"
99 #define PAGE2_MSG "2222PAGE2222"
100 #define END_MSG "E"
101 
TEST(sys_mman,mmap_file_read_at_offset)102 TEST(sys_mman, mmap_file_read_at_offset) {
103   TemporaryFile tf;
104   size_t pagesize = sysconf(_SC_PAGESIZE);
105 
106   // Create the file with three pages worth of data.
107   ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
108   ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
109   ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
110   ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
111   ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
112   ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
113   ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
114 
115   ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
116 
117   void* map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize);
118   ASSERT_NE(MAP_FAILED, map);
119 
120   char* data = reinterpret_cast<char*>(map);
121   ASSERT_STREQ(PAGE1_MSG, data);
122 
123   ASSERT_EQ(0, munmap(map, pagesize));
124 
125   map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize);
126   ASSERT_NE(MAP_FAILED, map);
127 
128   data = reinterpret_cast<char*>(map);
129   ASSERT_STREQ(PAGE2_MSG, data);
130   ASSERT_STREQ(END_MSG, data+pagesize-sizeof(END_MSG));
131 
132   ASSERT_EQ(0, munmap(map, pagesize));
133 }
134 
135 #define NEWPAGE1_MSG "1NEW1PAGE1"
136 #define NEWPAGE2_MSG "22NEW22PAGE22"
137 
TEST(sys_mman,mmap_file_write_at_offset)138 TEST(sys_mman, mmap_file_write_at_offset) {
139   TemporaryFile tf;
140   size_t pagesize = sysconf(_SC_PAGESIZE);
141 
142   // Create the file with three pages worth of data.
143   ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
144   ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
145   ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
146   ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
147   ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
148   ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
149   ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
150 
151   ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
152 
153   void* map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize);
154   ASSERT_NE(MAP_FAILED, map);
155   close(tf.fd);
156 
157   memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG));
158   ASSERT_EQ(0, munmap(map, pagesize));
159 
160   tf.fd = open(tf.path, O_RDWR);
161   map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
162   ASSERT_NE(MAP_FAILED, map);
163   close(tf.fd);
164 
165   memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG));
166   ASSERT_EQ(0, munmap(map, pagesize));
167 
168   tf.fd = open(tf.path, O_RDWR);
169   char buf[pagesize];
170   ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
171   ASSERT_STREQ(PAGE0_MSG, buf);
172   ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
173   ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
174   ASSERT_STREQ(NEWPAGE1_MSG, buf);
175   ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
176   ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
177   ASSERT_STREQ(NEWPAGE2_MSG, buf);
178   ASSERT_STREQ(END_MSG, buf+pagesize-sizeof(END_MSG));
179 }
180 
TEST(sys_mman,posix_madvise)181 TEST(sys_mman, posix_madvise) {
182   TemporaryFile tempfile;
183   size_t pagesize = sysconf(_SC_PAGESIZE);
184   char buf[pagesize];
185 
186   // Prepare environment.
187   ASSERT_EQ(static_cast<ssize_t>(pagesize), write(tempfile.fd, buf, pagesize));
188   void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0);
189   ASSERT_NE(MAP_FAILED, map);
190 
191   // Verify different options of posix_madvise.
192   ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_NORMAL));
193   ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_SEQUENTIAL));
194   ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_RANDOM));
195   ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_WILLNEED));
196 
197   ASSERT_EQ(0, munmap(map, pagesize));
198 }
199 
200 // Verify that memory can still access after posix_madvise(POSIX_MADV_DONTNEED).
201 // We should test on MAP_ANONYMOUS memory to verify whether the memory is discarded,
202 // because the content of non MAP_ANONYMOUS memory can be reread from file.
TEST(sys_mman,posix_madvise_POSIX_MADV_DONTNEED)203 TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) {
204   size_t pagesize = sysconf(_SC_PAGESIZE);
205 
206   void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
207   ASSERT_NE(MAP_FAILED, map);
208 
209   int* int_ptr = reinterpret_cast<int*>(map);
210   for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) {
211     *int_ptr++ = i;
212   }
213 
214   ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_DONTNEED));
215 
216   int_ptr = reinterpret_cast<int*>(map);
217   for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) {
218     ASSERT_EQ(i, *int_ptr++);
219   }
220 
221   ASSERT_EQ(0, munmap(map, pagesize));
222 }
223 
TEST(sys_mman,mremap)224 TEST(sys_mman, mremap) {
225 #pragma clang diagnostic push
226 #pragma clang diagnostic ignored "-Wnonnull"
227   ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
228 #pragma clang diagnostic pop
229 }
230 
231 constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1;
232 
TEST(sys_mman,mmap_PTRDIFF_MAX)233 TEST(sys_mman, mmap_PTRDIFF_MAX) {
234   ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
235 }
236 
TEST(sys_mman,mremap_PTRDIFF_MAX)237 TEST(sys_mman, mremap_PTRDIFF_MAX) {
238   void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
239   ASSERT_NE(MAP_FAILED, map);
240 
241   ASSERT_EQ(MAP_FAILED, mremap(map, kPageSize, kHuge, MREMAP_MAYMOVE));
242 
243   ASSERT_EQ(0, munmap(map, kPageSize));
244 }
245 
TEST(sys_mman,mremap_MREMAP_FIXED)246 TEST(sys_mman, mremap_MREMAP_FIXED) {
247   // We're not trying to test the kernel here; that's external/ltp's job.
248   // We just want to check that optional argument (mremap() is varargs)
249   // gets passed through in an MREMAP_FIXED call.
250   void* vma1 = mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
251   ASSERT_NE(MAP_FAILED, vma1);
252 
253   void* vma2 = mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
254   ASSERT_NE(MAP_FAILED, vma2);
255 
256   void* vma3 = mremap(vma1, getpagesize(), getpagesize(), MREMAP_FIXED | MREMAP_MAYMOVE, vma2);
257   ASSERT_EQ(vma2, vma3);
258 }
259 
TEST(sys_mman,mmap_bug_27265969)260 TEST(sys_mman, mmap_bug_27265969) {
261   char* base = reinterpret_cast<char*>(
262       mmap(nullptr, kPageSize * 2, PROT_EXEC | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
263   // Some kernels had bugs that would cause segfaults here...
264   __builtin___clear_cache(base, base + (kPageSize * 2));
265 }
266 
TEST(sys_mman,mlock)267 TEST(sys_mman, mlock) {
268   void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
269   ASSERT_NE(MAP_FAILED, map);
270 
271   // Not really anything we can assert about this.
272   mlock(map, kPageSize);
273 
274   ASSERT_EQ(0, munmap(map, kPageSize));
275 }
276 
TEST(sys_mman,mlock2)277 TEST(sys_mman, mlock2) {
278 #if defined(__GLIBC__)
279   GTEST_SKIP() << "needs glibc 2.27";
280 #else
281   void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
282   ASSERT_NE(MAP_FAILED, map);
283 
284   // Not really anything we can assert about this.
285   mlock2(map, kPageSize, MLOCK_ONFAULT);
286 
287   ASSERT_EQ(0, munmap(map, kPageSize));
288 #endif
289 }
290 
TEST(sys_mman,memfd_create)291 TEST(sys_mman, memfd_create) {
292 #if defined(__GLIBC__)
293   GTEST_SKIP() << "needs glibc 2.27";
294 #else
295   // Is the MFD_CLOEXEC flag obeyed?
296   errno = 0;
297   int fd = memfd_create("doesn't matter", 0);
298   if (fd == -1 && errno == ENOSYS) GTEST_SKIP() << "no memfd_create() in this kernel";
299   ASSERT_NE(-1, fd) << strerror(errno);
300 
301   int f = fcntl(fd, F_GETFD);
302   ASSERT_NE(-1, f);
303   ASSERT_FALSE(f & FD_CLOEXEC);
304   close(fd);
305 
306   errno = 0;
307   fd = memfd_create("doesn't matter", MFD_CLOEXEC);
308   f = fcntl(fd, F_GETFD);
309   ASSERT_NE(-1, f);
310   ASSERT_TRUE(f & FD_CLOEXEC);
311 
312   // Can we read and write?
313   std::string expected("hello, world!");
314   ASSERT_TRUE(android::base::WriteStringToFd(expected, fd));
315   ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
316   std::string actual;
317   ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
318   ASSERT_EQ(expected, actual);
319 
320   close(fd);
321 #endif
322 }
323