blob: 803852a2f97d8d79b67f095f8745293f0a9c3082 [file] [log] [blame]
Elliott Hughes431166d2014-01-27 16:28:31 -08001/*
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
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080017#include <fcntl.h>
Elliott Hughes431166d2014-01-27 16:28:31 -080018#include <sys/mman.h>
Josh Gao2feb9dd2015-11-19 13:44:20 -080019#include <sys/user.h>
Christopher Ferriseda26bc2014-06-12 13:16:36 -070020#include <sys/types.h>
Elliott Hughes431166d2014-01-27 16:28:31 -080021#include <unistd.h>
22
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080023#include <android-base/file.h>
24#include <gtest/gtest.h>
Christopher Ferriseda26bc2014-06-12 13:16:36 -070025
26TEST(sys_mman, mmap_std) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070027 void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070028 ASSERT_NE(MAP_FAILED, map);
29 ASSERT_EQ(0, munmap(map, 4096));
Elliott Hughes431166d2014-01-27 16:28:31 -080030}
31
Christopher Ferriseda26bc2014-06-12 13:16:36 -070032TEST(sys_mman, mmap64_std) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070033 void* map = mmap64(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070034 ASSERT_NE(MAP_FAILED, map);
35 ASSERT_EQ(0, munmap(map, 4096));
36}
37
38TEST(sys_mman, mmap_file_bad_offset) {
39 TemporaryFile tf;
40
Yi Kong32bc0fc2018-08-02 17:31:13 -070041 void* map = mmap(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070042 ASSERT_EQ(MAP_FAILED, map);
43}
44
45TEST(sys_mman, mmap64_file_bad_offset) {
46 TemporaryFile tf;
47
Yi Kong32bc0fc2018-08-02 17:31:13 -070048 void* map = mmap64(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070049 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
57TEST(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
Yi Kong32bc0fc2018-08-02 17:31:13 -070062 void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070063 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
71TEST(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
Yi Kong32bc0fc2018-08-02 17:31:13 -070077 void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070078 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
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080085 tf.fd = open(tf.path, O_RDWR);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070086 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
98TEST(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
Yi Kong32bc0fc2018-08-02 17:31:13 -0700113 void* map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700114 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
Yi Kong32bc0fc2018-08-02 17:31:13 -0700121 map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700122 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
134TEST(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
Yi Kong32bc0fc2018-08-02 17:31:13 -0700149 void* map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700150 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
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800156 tf.fd = open(tf.path, O_RDWR);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700157 map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700158 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
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800164 tf.fd = open(tf.path, O_RDWR);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700165 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));
Elliott Hughes431166d2014-01-27 16:28:31 -0800175}
Yabin Cui5afae642014-11-25 20:17:27 -0800176
177TEST(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));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700184 void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0);
Yabin Cui5afae642014-11-25 20:17:27 -0800185 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.
199TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) {
200 size_t pagesize = sysconf(_SC_PAGESIZE);
201
Yi Kong32bc0fc2018-08-02 17:31:13 -0700202 void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Yabin Cui5afae642014-11-25 20:17:27 -0800203 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}
Daniel Micay4200e262015-11-03 05:14:08 -0500219
220TEST(sys_mman, mremap) {
zijunzhao25725712023-05-04 23:29:00 +0000221#pragma clang diagnostic push
222#pragma clang diagnostic ignored "-Wnonnull"
Daniel Micay4200e262015-11-03 05:14:08 -0500223 ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
zijunzhao25725712023-05-04 23:29:00 +0000224#pragma clang diagnostic pop
Daniel Micay4200e262015-11-03 05:14:08 -0500225}
Daniel Micayc22a7de2015-11-07 10:40:26 -0500226
Elliott Hughes4a253492016-07-14 17:07:17 -0700227constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1;
Daniel Micayc22a7de2015-11-07 10:40:26 -0500228
229TEST(sys_mman, mmap_PTRDIFF_MAX) {
Elliott Hughes4a253492016-07-14 17:07:17 -0700230 ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
Daniel Micayc22a7de2015-11-07 10:40:26 -0500231}
232
233TEST(sys_mman, mremap_PTRDIFF_MAX) {
234 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
235 ASSERT_NE(MAP_FAILED, map);
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700236
Elliott Hughes4a253492016-07-14 17:07:17 -0700237 ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700238
239 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
Elliott Hughes4a253492016-07-14 17:07:17 -0700240}
241
242TEST(sys_mman, mmap_bug_27265969) {
243 char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ,
Elliott Hughes7b0af7a2017-09-15 16:09:22 -0700244 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
Elliott Hughes4a253492016-07-14 17:07:17 -0700245 // Some kernels had bugs that would cause segfaults here...
246 __builtin___clear_cache(base, base + (PAGE_SIZE * 2));
Daniel Micayc22a7de2015-11-07 10:40:26 -0500247}
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700248
249TEST(sys_mman, mlock) {
250 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
251 ASSERT_NE(MAP_FAILED, map);
252
253 // Not really anything we can assert about this.
254 mlock(map, PAGE_SIZE);
255
256 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
257}
258
259TEST(sys_mman, mlock2) {
260#if defined(__GLIBC__)
261 GTEST_SKIP() << "needs glibc 2.27";
262#else
263 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
264 ASSERT_NE(MAP_FAILED, map);
265
266 // Not really anything we can assert about this.
267 mlock2(map, PAGE_SIZE, MLOCK_ONFAULT);
268
269 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
270#endif
271}
272
273TEST(sys_mman, memfd_create) {
274#if defined(__GLIBC__)
275 GTEST_SKIP() << "needs glibc 2.27";
276#else
277 // Is the MFD_CLOEXEC flag obeyed?
278 errno = 0;
279 int fd = memfd_create("doesn't matter", 0);
280 if (fd == -1) {
281 ASSERT_EQ(ENOSYS, errno);
282 GTEST_SKIP() << "no memfd_create available";
283 }
284 int f = fcntl(fd, F_GETFD);
285 ASSERT_NE(-1, f);
286 ASSERT_FALSE(f & FD_CLOEXEC);
287 close(fd);
288
289 errno = 0;
290 fd = memfd_create("doesn't matter", MFD_CLOEXEC);
291 f = fcntl(fd, F_GETFD);
292 ASSERT_NE(-1, f);
293 ASSERT_TRUE(f & FD_CLOEXEC);
294
295 // Can we read and write?
296 std::string expected("hello, world!");
297 ASSERT_TRUE(android::base::WriteStringToFd(expected, fd));
298 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
299 std::string actual;
300 ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
301 ASSERT_EQ(expected, actual);
302
303 close(fd);
304#endif
305}