• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2392

06 Jun 2024 05:02PM UTC coverage: 90.987% (+0.1%) from 90.855%
2392

push

Evergreen

web-flow
Merge pull request #7698 from realm/tg/file-map-cache

RCORE-2141 RCORE-2142 Clean up a bunch of old encryption cruft

101862 of 180058 branches covered (56.57%)

1048 of 1098 new or added lines in 27 files covered. (95.45%)

118 existing lines in 19 files now uncovered.

214614 of 235872 relevant lines covered (90.99%)

5960870.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.13
/src/realm/util/file_mapper.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/util/file_mapper.hpp>
20

21
#include <realm/exceptions.hpp>
22
#include <realm/impl/simulated_failure.hpp>
23
#include <realm/util/errno.hpp>
24
#include <realm/util/features.h>
25
#include <realm/util/to_string.hpp>
26

27
#include <system_error>
28

29
#ifdef _WIN32
30
#include <windows.h>
31
#else
32
#include <cerrno>
33
#include <sys/mman.h>
34
#endif
35

36
#if REALM_ENABLE_ENCRYPTION
37

38
#include <realm/util/encrypted_file_mapping.hpp>
39
#include <realm/util/aes_cryptor.hpp>
40
#include <realm/util/scope_exit.hpp>
41
#include <realm/util/terminate.hpp>
42

43
#include <atomic>
44
#include <memory>
45
#include <csignal>
46
#include <sys/stat.h>
47
#include <cstring>
48
#include <atomic>
49
#include <thread>
50
#include <cstring> // for memset
51

52
#if REALM_PLATFORM_APPLE
53
#include <dispatch/dispatch.h>
54
#endif
55

56
#endif // enable encryption
57

58
namespace {
59
inline bool is_mmap_memory_error(int err)
UNCOV
60
{
×
61
    return (err == EAGAIN || err == EMFILE || err == ENOMEM);
×
62
}
×
63
} // Unnamed namespace
64

65
namespace realm::util {
66
size_t round_up_to_page_size(size_t size) noexcept
67
{
288,447✔
68
    auto ps = page_size();
288,447✔
69
    return (size + ps - 1) & ~(ps - 1);
288,447✔
70
}
288,447✔
71

72
void* mmap(const FileAttributes& file, size_t size, uint64_t offset, std::unique_ptr<EncryptedFileMapping>& mapping)
73
{
1,426,776✔
74
    _impl::SimulatedFailure::trigger_mmap(size);
1,426,776✔
75

76
#if REALM_ENABLE_ENCRYPTION
1,426,776✔
77
    if (file.encryption) {
1,426,776✔
78
        auto page_start = offset & ~(page_size() - 1);
36,135✔
79
        size += size_t(offset - page_start);
36,135✔
80
        size = round_up_to_page_size(size);
36,135✔
81
        void* addr = mmap_anon(size);
36,135✔
82
        ScopeExitFail cleanup([&]() noexcept {
36,135✔
NEW
83
            munmap(addr, size);
×
UNCOV
84
        });
×
85
        mapping = file.encryption->add_mapping(page_start, addr, size, file.access);
36,135✔
86
        return static_cast<char*>(addr) - page_start + offset;
36,135✔
87
    }
36,135✔
88
    mapping = nullptr;
1,390,641✔
89
#else
90
    static_cast<void>(mapping);
91
#endif
92

93
#ifndef _WIN32
1,390,641✔
94
    int prot = PROT_READ;
1,390,641✔
95
    switch (file.access) {
1,390,641✔
96
        case File::access_ReadWrite:
1,266,369✔
97
            prot |= PROT_WRITE;
1,266,369✔
98
            break;
1,266,369✔
99
        case File::access_ReadOnly:
124,257✔
100
            break;
124,257✔
101
    }
1,390,641✔
102

103
    void* addr = ::mmap(nullptr, size, prot, MAP_SHARED, file.fd, offset);
1,390,605✔
104
    if (addr != MAP_FAILED)
1,390,605✔
105
        return addr;
1,390,770✔
106

107
    int err = errno; // Eliminate any risk of clobbering
4,294,967,294✔
108
    if (is_mmap_memory_error(err)) {
4,294,967,294✔
NEW
109
        throw AddressSpaceExhausted(util::format("mmap() failed: %1 (size: %2, offset: %3)",
×
NEW
110
                                                 make_basic_system_error_code(err).message(), size, offset));
×
UNCOV
111
    }
×
112

113
    throw SystemError(err, util::format("mmap() failed (size: %1, offset: %2", size, offset));
4,294,967,294✔
114

115
#else
116
    DWORD protect = PAGE_READONLY;
117
    DWORD desired_access = FILE_MAP_READ;
118
    switch (file.access) {
119
        case File::access_ReadOnly:
120
            break;
121
        case File::access_ReadWrite:
122
            protect = PAGE_READWRITE;
123
            desired_access = FILE_MAP_WRITE;
124
            break;
125
    }
126
    LARGE_INTEGER large_int;
127
    if (int_cast_with_overflow_detect(offset + size, large_int.QuadPart))
128
        throw std::runtime_error("Map size is too large");
129
    HANDLE map_handle = CreateFileMappingFromApp(file.fd, 0, protect, offset + size, nullptr);
130
    if (!map_handle)
131
        throw AddressSpaceExhausted(get_errno_msg("CreateFileMapping() failed: ", GetLastError()) +
132
                                    " size: " + util::to_string(size) + " offset: " + util::to_string(offset));
133

134
    if (int_cast_with_overflow_detect(offset, large_int.QuadPart))
135
        throw RuntimeError(ErrorCodes::RangeError, "Map offset is too large");
136

137
    SIZE_T _size = size;
138
    void* addr = MapViewOfFileFromApp(map_handle, desired_access, offset, _size);
139
    BOOL r = CloseHandle(map_handle);
140
    REALM_ASSERT_RELEASE(r);
141
    if (!addr)
142
        throw AddressSpaceExhausted(get_errno_msg("MapViewOfFileFromApp() failed: ", GetLastError()) +
143
                                    " size: " + util::to_string(_size) + " offset: " + util::to_string(offset));
144

145
    return addr;
146
#endif
147
}
4,294,967,294✔
148

149
#if REALM_ENABLE_ENCRYPTION
150
std::unique_ptr<EncryptedFileMapping> reserve_mapping(void* addr, const FileAttributes& file, uint64_t offset)
151
{
306✔
152
    return file.encryption->add_mapping(offset, addr, 0, file.access);
306✔
153
}
306✔
154

155
#endif // REALM_ENABLE_ENCRYPTION
156

157
void* mmap_anon(size_t size)
158
{
36,135✔
159
#ifdef _WIN32
160
    HANDLE hMapFile;
161
    LPCTSTR pBuf;
162

163
    ULARGE_INTEGER s;
164
    s.QuadPart = size;
165

166
    hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, s.HighPart, s.LowPart, nullptr);
167
    if (hMapFile == NULL) {
168
        throw std::system_error(GetLastError(), std::system_category(), "CreateFileMapping() failed");
169
    }
170

171
    pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, size);
172
    if (pBuf == nullptr) {
173
        throw std::system_error(GetLastError(), std::system_category(), "MapViewOfFile() failed");
174
    }
175

176
    CloseHandle(hMapFile);
177
    return (void*)pBuf;
178
#else
179
    void* addr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
36,135✔
180
    if (addr == MAP_FAILED) {
36,135✔
181
        int err = errno; // Eliminate any risk of clobbering
×
182
        if (is_mmap_memory_error(err)) {
×
183
            throw AddressSpaceExhausted(get_errno_msg("mmap() failed: ", err) + " size: " + util::to_string(size));
×
184
        }
×
185
        throw std::system_error(err, std::system_category(),
×
186
                                std::string("mmap() failed (size: ") + util::to_string(size) + ", offset is 0)");
×
187
    }
×
188
    return addr;
36,135✔
189
#endif
36,135✔
190
}
36,135✔
191

192
#ifndef _WIN32
193
void* mmap_fixed(FileDesc fd, void* address_request, size_t size, File::AccessMode access, uint64_t offset)
194
{
118,350✔
195
    _impl::SimulatedFailure::trigger_mmap(size);
118,350✔
196
    auto prot = PROT_READ;
118,350✔
197
    if (access == File::access_ReadWrite)
118,350✔
198
        prot |= PROT_WRITE;
×
199
    auto addr = ::mmap(address_request, size, prot, MAP_SHARED | MAP_FIXED, fd, offset);
118,350✔
200
    if (addr != MAP_FAILED && addr != address_request) {
118,350✔
201
        throw std::runtime_error(get_errno_msg("mmap() failed: ", errno) +
×
202
                                 ", when mapping an already reserved memory area");
×
203
    }
×
204
    return addr;
118,350✔
205
}
118,350✔
206
#endif // _WIN32
207

208

209
void munmap(void* addr, size_t size)
210
{
1,525,089✔
211
    auto shift = reinterpret_cast<uintptr_t>(addr) & (page_size() - 1);
1,525,089✔
212
    addr = static_cast<char*>(addr) - shift;
1,525,089✔
213
    size += shift;
1,525,089✔
214
#ifdef _WIN32
215
    if (!UnmapViewOfFile(addr))
216
        throw std::system_error(GetLastError(), std::system_category(), "UnmapViewOfFile() failed");
217

218
#else
219
    if (::munmap(addr, size) != 0) {
1,525,089✔
220
        int err = errno;
×
221
        throw std::system_error(err, std::system_category(), "munmap() failed");
×
222
    }
×
223
#endif
1,525,089✔
224
}
1,525,089✔
225

226
void msync(FileDesc fd, void* addr, size_t size)
227
{
1,398,084✔
228
#ifdef _WIN32
229
    // FlushViewOfFile() is asynchronous and won't flush metadata (file size, etc)
230
    if (!FlushViewOfFile(addr, size)) {
231
        throw std::system_error(GetLastError(), std::system_category(), "FlushViewOfFile() failed");
232
    }
233
    // Block until data and metadata is written physically to the media
234
    if (!FlushFileBuffers(fd)) {
235
        throw std::system_error(GetLastError(), std::system_category(), "FlushFileBuffers() failed");
236
    }
237
    return;
238
#else
239
    static_cast<void>(fd);
1,398,084✔
240
    int retries_left = 1000;
1,398,084✔
241
    while (::msync(addr, size, MS_SYNC) != 0) {
1,398,084✔
242
        int err = errno; // Eliminate any risk of clobbering
×
243
        if (--retries_left < 0)
×
244
            throw std::system_error(err, std::system_category(), "msync() retries exhausted");
×
245
        if (err != EINTR)
×
246
            throw std::system_error(err, std::system_category(), "msync() failed");
×
247
    }
×
248
#endif
1,398,084✔
249
}
1,398,084✔
250

251
#if REALM_ENABLE_ENCRYPTION
252
void do_encryption_read_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping, bool to_modify)
253
{
6,790,749✔
254
    mapping->read_barrier(addr, size, to_modify);
6,790,749✔
255
}
6,790,749✔
256

257
void do_encryption_write_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping)
258
{
2,342,361✔
259
    mapping->write_barrier(addr, size);
2,342,361✔
260
}
2,342,361✔
261
#endif // REALM_ENABLE_ENCRYPTION
262

263
} // namespace realm::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc