blob: e785ff44b86b7e816dd2fdeb0a877d9fc0fef8f0 [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
Elliott Hughes95646e62023-09-21 14:11:19 -070026#include "utils.h"
27
Christopher Ferriseda26bc2014-06-12 13:16:36 -070028TEST(sys_mman, mmap_std) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070029 void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070030 ASSERT_NE(MAP_FAILED, map);
31 ASSERT_EQ(0, munmap(map, 4096));
Elliott Hughes431166d2014-01-27 16:28:31 -080032}
33
Christopher Ferriseda26bc2014-06-12 13:16:36 -070034TEST(sys_mman, mmap64_std) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070035 void* map = mmap64(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070036 ASSERT_NE(MAP_FAILED, map);
37 ASSERT_EQ(0, munmap(map, 4096));
38}
39
40TEST(sys_mman, mmap_file_bad_offset) {
41 TemporaryFile tf;
42
Yi Kong32bc0fc2018-08-02 17:31:13 -070043 void* map = mmap(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070044 ASSERT_EQ(MAP_FAILED, map);
45}
46
47TEST(sys_mman, mmap64_file_bad_offset) {
48 TemporaryFile tf;
49
Yi Kong32bc0fc2018-08-02 17:31:13 -070050 void* map = mmap64(nullptr, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070051 ASSERT_EQ(MAP_FAILED, map);
52}
53
54#define STR_SSIZE(str) static_cast<ssize_t>(sizeof(str))
55
56#define STRING_MSG "012345678\nabcdefgh\n"
57#define INITIAL_MSG "000000000\n00000000\n"
58
59TEST(sys_mman, mmap_file_read) {
60 TemporaryFile tf;
61
62 ASSERT_EQ(STR_SSIZE(STRING_MSG), write(tf.fd, STRING_MSG, sizeof(STRING_MSG)));
63
Yi Kong32bc0fc2018-08-02 17:31:13 -070064 void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070065 ASSERT_NE(MAP_FAILED, map);
66
67 char* data = reinterpret_cast<char*>(map);
68 ASSERT_STREQ(STRING_MSG, data);
69
70 ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
71}
72
73TEST(sys_mman, mmap_file_write) {
74 TemporaryFile tf;
75
76 ASSERT_EQ(STR_SSIZE(INITIAL_MSG), write(tf.fd, INITIAL_MSG, sizeof(INITIAL_MSG)));
77 lseek(tf.fd, 0, SEEK_SET);
78
Yi Kong32bc0fc2018-08-02 17:31:13 -070079 void* map = mmap(nullptr, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070080 ASSERT_NE(MAP_FAILED, map);
81 close(tf.fd);
82
83 memcpy(map, STRING_MSG, sizeof(STRING_MSG));
84
85 ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
86
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080087 tf.fd = open(tf.path, O_RDWR);
Christopher Ferriseda26bc2014-06-12 13:16:36 -070088 char buf[sizeof(STRING_MSG)];
89 memset(buf, 0, sizeof(STRING_MSG));
90 ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG)));
91
92 ASSERT_STREQ(STRING_MSG, buf);
93}
94
95#define PAGE0_MSG "00PAGE00"
96#define PAGE1_MSG "111PAGE111"
97#define PAGE2_MSG "2222PAGE2222"
98#define END_MSG "E"
99
100TEST(sys_mman, mmap_file_read_at_offset) {
101 TemporaryFile tf;
102 size_t pagesize = sysconf(_SC_PAGESIZE);
103
104 // Create the file with three pages worth of data.
105 ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
106 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
107 ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
108 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
109 ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
110 ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
111 ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
112
113 ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
114
Yi Kong32bc0fc2018-08-02 17:31:13 -0700115 void* map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700116 ASSERT_NE(MAP_FAILED, map);
117
118 char* data = reinterpret_cast<char*>(map);
119 ASSERT_STREQ(PAGE1_MSG, data);
120
121 ASSERT_EQ(0, munmap(map, pagesize));
122
Yi Kong32bc0fc2018-08-02 17:31:13 -0700123 map = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700124 ASSERT_NE(MAP_FAILED, map);
125
126 data = reinterpret_cast<char*>(map);
127 ASSERT_STREQ(PAGE2_MSG, data);
128 ASSERT_STREQ(END_MSG, data+pagesize-sizeof(END_MSG));
129
130 ASSERT_EQ(0, munmap(map, pagesize));
131}
132
133#define NEWPAGE1_MSG "1NEW1PAGE1"
134#define NEWPAGE2_MSG "22NEW22PAGE22"
135
136TEST(sys_mman, mmap_file_write_at_offset) {
137 TemporaryFile tf;
138 size_t pagesize = sysconf(_SC_PAGESIZE);
139
140 // Create the file with three pages worth of data.
141 ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
142 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
143 ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
144 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
145 ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
146 ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
147 ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
148
149 ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
150
Yi Kong32bc0fc2018-08-02 17:31:13 -0700151 void* map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700152 ASSERT_NE(MAP_FAILED, map);
153 close(tf.fd);
154
155 memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG));
156 ASSERT_EQ(0, munmap(map, pagesize));
157
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800158 tf.fd = open(tf.path, O_RDWR);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700159 map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700160 ASSERT_NE(MAP_FAILED, map);
161 close(tf.fd);
162
163 memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG));
164 ASSERT_EQ(0, munmap(map, pagesize));
165
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800166 tf.fd = open(tf.path, O_RDWR);
Christopher Ferriseda26bc2014-06-12 13:16:36 -0700167 char buf[pagesize];
168 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
169 ASSERT_STREQ(PAGE0_MSG, buf);
170 ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
171 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
172 ASSERT_STREQ(NEWPAGE1_MSG, buf);
173 ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
174 ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
175 ASSERT_STREQ(NEWPAGE2_MSG, buf);
176 ASSERT_STREQ(END_MSG, buf+pagesize-sizeof(END_MSG));
Elliott Hughes431166d2014-01-27 16:28:31 -0800177}
Yabin Cui5afae642014-11-25 20:17:27 -0800178
179TEST(sys_mman, posix_madvise) {
180 TemporaryFile tempfile;
181 size_t pagesize = sysconf(_SC_PAGESIZE);
182 char buf[pagesize];
183
184 // Prepare environment.
185 ASSERT_EQ(static_cast<ssize_t>(pagesize), write(tempfile.fd, buf, pagesize));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700186 void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0);
Yabin Cui5afae642014-11-25 20:17:27 -0800187 ASSERT_NE(MAP_FAILED, map);
188
189 // Verify different options of posix_madvise.
190 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_NORMAL));
191 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_SEQUENTIAL));
192 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_RANDOM));
193 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_WILLNEED));
194
195 ASSERT_EQ(0, munmap(map, pagesize));
196}
197
198// Verify that memory can still access after posix_madvise(POSIX_MADV_DONTNEED).
199// We should test on MAP_ANONYMOUS memory to verify whether the memory is discarded,
200// because the content of non MAP_ANONYMOUS memory can be reread from file.
201TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) {
202 size_t pagesize = sysconf(_SC_PAGESIZE);
203
Yi Kong32bc0fc2018-08-02 17:31:13 -0700204 void* map = mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Yabin Cui5afae642014-11-25 20:17:27 -0800205 ASSERT_NE(MAP_FAILED, map);
206
207 int* int_ptr = reinterpret_cast<int*>(map);
208 for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) {
209 *int_ptr++ = i;
210 }
211
212 ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_DONTNEED));
213
214 int_ptr = reinterpret_cast<int*>(map);
215 for (int i = 0; i < static_cast<int>(pagesize / sizeof(int)); ++i) {
216 ASSERT_EQ(i, *int_ptr++);
217 }
218
219 ASSERT_EQ(0, munmap(map, pagesize));
220}
Daniel Micay4200e262015-11-03 05:14:08 -0500221
222TEST(sys_mman, mremap) {
zijunzhao25725712023-05-04 23:29:00 +0000223#pragma clang diagnostic push
224#pragma clang diagnostic ignored "-Wnonnull"
Daniel Micay4200e262015-11-03 05:14:08 -0500225 ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
zijunzhao25725712023-05-04 23:29:00 +0000226#pragma clang diagnostic pop
Daniel Micay4200e262015-11-03 05:14:08 -0500227}
Daniel Micayc22a7de2015-11-07 10:40:26 -0500228
Elliott Hughes4a253492016-07-14 17:07:17 -0700229constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1;
Daniel Micayc22a7de2015-11-07 10:40:26 -0500230
231TEST(sys_mman, mmap_PTRDIFF_MAX) {
Elliott Hughes4a253492016-07-14 17:07:17 -0700232 ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
Daniel Micayc22a7de2015-11-07 10:40:26 -0500233}
234
235TEST(sys_mman, mremap_PTRDIFF_MAX) {
236 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
237 ASSERT_NE(MAP_FAILED, map);
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700238
Elliott Hughes4a253492016-07-14 17:07:17 -0700239 ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700240
241 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
Elliott Hughes4a253492016-07-14 17:07:17 -0700242}
243
244TEST(sys_mman, mmap_bug_27265969) {
245 char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ,
Elliott Hughes7b0af7a2017-09-15 16:09:22 -0700246 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
Elliott Hughes4a253492016-07-14 17:07:17 -0700247 // Some kernels had bugs that would cause segfaults here...
248 __builtin___clear_cache(base, base + (PAGE_SIZE * 2));
Daniel Micayc22a7de2015-11-07 10:40:26 -0500249}
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700250
251TEST(sys_mman, mlock) {
252 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
253 ASSERT_NE(MAP_FAILED, map);
254
255 // Not really anything we can assert about this.
256 mlock(map, PAGE_SIZE);
257
258 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
259}
260
261TEST(sys_mman, mlock2) {
262#if defined(__GLIBC__)
263 GTEST_SKIP() << "needs glibc 2.27";
264#else
265 void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
266 ASSERT_NE(MAP_FAILED, map);
267
268 // Not really anything we can assert about this.
269 mlock2(map, PAGE_SIZE, MLOCK_ONFAULT);
270
271 ASSERT_EQ(0, munmap(map, PAGE_SIZE));
272#endif
273}
274
275TEST(sys_mman, memfd_create) {
276#if defined(__GLIBC__)
277 GTEST_SKIP() << "needs glibc 2.27";
278#else
279 // Is the MFD_CLOEXEC flag obeyed?
280 errno = 0;
281 int fd = memfd_create("doesn't matter", 0);
Elliott Hughes4ae4be92023-09-22 17:15:25 -0700282 if (fd == -1 && errno == ENOSYS) GTEST_SKIP() << "no memfd_create() in this kernel";
283 ASSERT_NE(-1, fd) << strerror(errno);
284
Elliott Hughes3d24d2b2019-08-05 13:53:01 -0700285 int f = fcntl(fd, F_GETFD);
286 ASSERT_NE(-1, f);
287 ASSERT_FALSE(f & FD_CLOEXEC);
288 close(fd);
289
290 errno = 0;
291 fd = memfd_create("doesn't matter", MFD_CLOEXEC);
292 f = fcntl(fd, F_GETFD);
293 ASSERT_NE(-1, f);
294 ASSERT_TRUE(f & FD_CLOEXEC);
295
296 // Can we read and write?
297 std::string expected("hello, world!");
298 ASSERT_TRUE(android::base::WriteStringToFd(expected, fd));
299 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
300 std::string actual;
301 ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
302 ASSERT_EQ(expected, actual);
303
304 close(fd);
305#endif
306}