github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/msync.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <sys/mman.h>
    16  #include <unistd.h>
    17  
    18  #include <functional>
    19  #include <string>
    20  #include <utility>
    21  #include <vector>
    22  
    23  #include "test/util/file_descriptor.h"
    24  #include "test/util/memory_util.h"
    25  #include "test/util/posix_error.h"
    26  #include "test/util/temp_path.h"
    27  #include "test/util/test_util.h"
    28  
    29  namespace gvisor {
    30  namespace testing {
    31  
    32  namespace {
    33  
    34  // Parameters for msync tests. Use a std::tuple so we can use
    35  // ::testing::Combine.
    36  using MsyncTestParam =
    37      std::tuple<int,                                    // msync flags
    38                 std::function<PosixErrorOr<Mapping>()>  // returns mapping to
    39                                                         // msync
    40                 >;
    41  
    42  class MsyncParameterizedTest : public ::testing::TestWithParam<MsyncTestParam> {
    43   protected:
    44    int msync_flags() const { return std::get<0>(GetParam()); }
    45  
    46    PosixErrorOr<Mapping> GetMapping() const { return std::get<1>(GetParam())(); }
    47  };
    48  
    49  // All valid msync(2) flag combinations, not including MS_INVALIDATE. ("Linux
    50  // permits a call to msync() that specifies neither [MS_SYNC or MS_ASYNC], with
    51  // semantics that are (currently) equivalent to specifying MS_ASYNC." -
    52  // msync(2))
    53  constexpr std::initializer_list<int> kMsyncFlags = {MS_SYNC, MS_ASYNC, 0};
    54  
    55  // Returns functions that return mappings that should be successfully
    56  // msync()able.
    57  std::vector<std::function<PosixErrorOr<Mapping>()>> SyncableMappings() {
    58    std::vector<std::function<PosixErrorOr<Mapping>()>> funcs;
    59    for (bool const writable : {false, true}) {
    60      for (int const mflags : {MAP_PRIVATE, MAP_SHARED}) {
    61        int const prot = PROT_READ | (writable ? PROT_WRITE : 0);
    62        int const oflags = O_CREAT | (writable ? O_RDWR : O_RDONLY);
    63        funcs.push_back([=] { return MmapAnon(kPageSize, prot, mflags); });
    64        funcs.push_back([=]() -> PosixErrorOr<Mapping> {
    65          std::string const path = NewTempAbsPath();
    66          ASSIGN_OR_RETURN_ERRNO(auto fd, Open(path, oflags, 0644));
    67          // Don't unlink the file since that breaks save/restore. Just let the
    68          // test infrastructure clean up all of our temporary files when we're
    69          // done.
    70          return Mmap(nullptr, kPageSize, prot, mflags, fd.get(), 0);
    71        });
    72      }
    73    }
    74    return funcs;
    75  }
    76  
    77  PosixErrorOr<Mapping> NoMappings() {
    78    return PosixError(EINVAL, "unexpected attempt to create a mapping");
    79  }
    80  
    81  // "Fixture" for msync tests that hold for all valid flags, but do not create
    82  // mappings.
    83  using MsyncNoMappingTest = MsyncParameterizedTest;
    84  
    85  TEST_P(MsyncNoMappingTest, UnmappedAddressWithZeroLengthSucceeds) {
    86    EXPECT_THAT(msync(nullptr, 0, msync_flags()), SyscallSucceeds());
    87  }
    88  
    89  TEST_P(MsyncNoMappingTest, UnmappedAddressWithNonzeroLengthFails) {
    90    EXPECT_THAT(msync(nullptr, kPageSize, msync_flags()),
    91                SyscallFailsWithErrno(ENOMEM));
    92  }
    93  
    94  INSTANTIATE_TEST_SUITE_P(All, MsyncNoMappingTest,
    95                           ::testing::Combine(::testing::ValuesIn(kMsyncFlags),
    96                                              ::testing::Values(NoMappings)));
    97  
    98  // "Fixture" for msync tests that are not parameterized by msync flags, but do
    99  // create mappings.
   100  using MsyncNoFlagsTest = MsyncParameterizedTest;
   101  
   102  TEST_P(MsyncNoFlagsTest, BothSyncAndAsyncFails) {
   103    auto m = ASSERT_NO_ERRNO_AND_VALUE(GetMapping());
   104    EXPECT_THAT(msync(m.ptr(), m.len(), MS_SYNC | MS_ASYNC),
   105                SyscallFailsWithErrno(EINVAL));
   106  }
   107  
   108  INSTANTIATE_TEST_SUITE_P(
   109      All, MsyncNoFlagsTest,
   110      ::testing::Combine(::testing::Values(0),  // ignored
   111                         ::testing::ValuesIn(SyncableMappings())));
   112  
   113  // "Fixture" for msync tests parameterized by both msync flags and sources of
   114  // mappings.
   115  using MsyncFullParamTest = MsyncParameterizedTest;
   116  
   117  TEST_P(MsyncFullParamTest, NormallySucceeds) {
   118    auto m = ASSERT_NO_ERRNO_AND_VALUE(GetMapping());
   119    EXPECT_THAT(msync(m.ptr(), m.len(), msync_flags()), SyscallSucceeds());
   120  }
   121  
   122  TEST_P(MsyncFullParamTest, UnalignedLengthSucceeds) {
   123    auto m = ASSERT_NO_ERRNO_AND_VALUE(GetMapping());
   124    EXPECT_THAT(msync(m.ptr(), m.len() - 1, msync_flags()), SyscallSucceeds());
   125  }
   126  
   127  TEST_P(MsyncFullParamTest, UnalignedAddressFails) {
   128    auto m = ASSERT_NO_ERRNO_AND_VALUE(GetMapping());
   129    EXPECT_THAT(
   130        msync(reinterpret_cast<void*>(m.addr() + 1), m.len() - 1, msync_flags()),
   131        SyscallFailsWithErrno(EINVAL));
   132  }
   133  
   134  TEST_P(MsyncFullParamTest, InvalidateUnlockedSucceeds) {
   135    auto m = ASSERT_NO_ERRNO_AND_VALUE(GetMapping());
   136    EXPECT_THAT(msync(m.ptr(), m.len(), msync_flags() | MS_INVALIDATE),
   137                SyscallSucceeds());
   138  }
   139  
   140  // The test for MS_INVALIDATE on mlocked pages is in mlock.cc since it requires
   141  // probing for mlock support.
   142  
   143  INSTANTIATE_TEST_SUITE_P(
   144      All, MsyncFullParamTest,
   145      ::testing::Combine(::testing::ValuesIn(kMsyncFlags),
   146                         ::testing::ValuesIn(SyncableMappings())));
   147  
   148  }  // namespace
   149  
   150  }  // namespace testing
   151  }  // namespace gvisor