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/types.h>
     21 #include <unistd.h>
     22 
     23 #include "TemporaryFile.h"
     24 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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.
    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