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
TEST(sys_mman,mmap_std)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
TEST(sys_mman,mmap64_std)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
TEST(sys_mman,mmap_file_bad_offset)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
TEST(sys_mman,mmap64_file_bad_offset)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
TEST(sys_mman,mmap_file_read)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
TEST(sys_mman,mmap_file_write)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
TEST(sys_mman,mmap_file_read_at_offset)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
TEST(sys_mman,mmap_file_write_at_offset)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
TEST(sys_mman,posix_madvise)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.
TEST(sys_mman,posix_madvise_POSIX_MADV_DONTNEED)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