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
25TEST(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
31TEST(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
37TEST(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
44TEST(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
56TEST(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
70TEST(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
97TEST(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
133TEST(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