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