Home | History | Annotate | Download | only in tests
      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/user.h>
     21 #include <sys/types.h>
     22 #include <unistd.h>
     23 
     24 #include "TemporaryFile.h"
     25 
     26 TEST(sys_mman, mmap_std) {
     27   void* map = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
     28   ASSERT_NE(MAP_FAILED, map);
     29   ASSERT_EQ(0, munmap(map, 4096));
     30 }
     31 
     32 TEST(sys_mman, mmap64_std) {
     33   void* map = mmap64(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
     34   ASSERT_NE(MAP_FAILED, map);
     35   ASSERT_EQ(0, munmap(map, 4096));
     36 }
     37 
     38 TEST(sys_mman, mmap_file_bad_offset) {
     39   TemporaryFile tf;
     40 
     41   void* map = mmap(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
     42   ASSERT_EQ(MAP_FAILED, map);
     43 }
     44 
     45 TEST(sys_mman, mmap64_file_bad_offset) {
     46   TemporaryFile tf;
     47 
     48   void* map = mmap64(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
     49   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 
     57 TEST(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 
     62   void* map = mmap(NULL, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0);
     63   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 
     71 TEST(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 
     77   void* map = mmap(NULL, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0);
     78   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 
     85   tf.reopen();
     86   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 
     98 TEST(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 
    113   void* map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize);
    114   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 
    121   map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize);
    122   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 
    134 TEST(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 
    149   void* map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize);
    150   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 
    156   tf.reopen();
    157   map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
    158   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 
    164   tf.reopen();
    165   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));
    175 }
    176 
    177 TEST(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));
    184   void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0);
    185   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.
    199 TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) {
    200   size_t pagesize = sysconf(_SC_PAGESIZE);
    201 
    202   void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    203   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 }
    219 
    220 TEST(sys_mman, mremap) {
    221   ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
    222 }
    223 
    224 constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1;
    225 
    226 TEST(sys_mman, mmap_PTRDIFF_MAX) {
    227   ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
    228 }
    229 
    230 TEST(sys_mman, mremap_PTRDIFF_MAX) {
    231   void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    232   ASSERT_NE(MAP_FAILED, map);
    233   ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
    234 }
    235 
    236 TEST(sys_mman, mmap_bug_27265969) {
    237   char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ,
    238                                             MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
    239   // Some kernels had bugs that would cause segfaults here...
    240   __builtin___clear_cache(base, base + (PAGE_SIZE * 2));
    241 }
    242