Skip to content

Commit 42e4a85

Browse files
authored
Merge pull request #7698 from realm/tg/file-map-cache
RCORE-2141 RCORE-2142 Clean up a bunch of old encryption cruft
2 parents 948949a + 7ab83e8 commit 42e4a85

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2001
-3288
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
### Fixed
99
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
1010
* Fix some client resets (such as migrating to flexible sync) potentially failing with AutoClientResetFailed if a new client reset condition (such as rolling back a flexible sync migration) occurred before the first one completed. ([PR #7542](https://github.com/realm/realm-core/pull/7542), since v13.11.0)
11+
* Encrypted files on Windows had a maximum size of 2GB even on x64 due to internal usage of `off_t`, which is a 32-bit type on 64-bit Windows ([PR #7698](https://github.com/realm/realm-core/pull/7698), since the introduction of encryption support on Windows in v3.0.0).
12+
* The encryption code no longer behaves differently depending on the system page size, which should entirely eliminate a recurring source of bugs related to copying encrypted Realm files between platforms with different page sizes. One known outstanding bug was ([RNET-1141](https://github.com/realm/realm-dotnet/issues/3592)), where opening files on a system with a larger page size than the writing system would attempt to read sections of the file which had never been written to ([PR #7698](https://github.com/realm/realm-core/pull/7698)).
13+
* There were several complicated scenarios which could result in stale reads from encrypted files in multiprocess scenarios. These were very difficult to hit and would typically lead to a crash, either due to an assertion failure or DecryptionFailure being thrown ([PR #7698](https://github.com/realm/realm-core/pull/7698), since v13.9.0).
14+
* Encrypted files have some benign data races where we can memcpy a block of memory while another thread is writing to a limited range of it. It is logically impossible to ever read from that range when this happens, but Thread Sanitizer quite reasonably complains about this. We now perform a slower operations when running with TSan which avoids this benign race ([PR #7698](https://github.com/realm/realm-core/pull/7698)).
15+
* Tokenizing strings for full-text search could pass values outside the range [-1, 255] to `isspace()`, which is undefined behavior ([PR #7698](https://github.com/realm/realm-core/pull/7698), since the introduction of FTS in v13.0.0).
1116

1217
### Breaking changes
1318
* Any `stitch_` prefixed fields in the `BsonDocument` returned from `app::User::custom_data()` are being renamed on the server to have a `baas_` prefix instead ([PR #7769](https://github.com/realm/realm-core/pull/7769)).
@@ -21,6 +26,7 @@
2126
* Removed references to `stitch_` fields in access tokens in sync unit tests ([PR #7769](https://github.com/realm/realm-core/pull/7769)).
2227
* Added back iOS simulator testing to evergreen after Jenkins went away ([PR #7758](https://github.com/realm/realm-core/pull/7758)).
2328
* `realm-trawler -c` did not work on Realm using SyncClient history ([PR #7734](https://github.com/realm/realm-core/pull/7734)).
29+
* `File::Map`'s move constructor and assignment operator left `m_fd` unchanged, which appears to have never actually resulted in problems with how it was used ([PR #7698](https://github.com/realm/realm-core/pull/7698)).
2430

2531
----------------------------------------------
2632

src/realm/alloc.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ char* Allocator::translate_less_critical(RefTranslation* ref_translation_ptr, re
119119
RefTranslation& txl = ref_translation_ptr[idx];
120120
size_t offset = ref - get_section_base(idx);
121121
char* addr = txl.mapping_addr + offset;
122-
#if REALM_ENABLE_ENCRYPTION
123-
realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping, nullptr);
124-
#endif
122+
util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping);
125123
auto size = NodeHeader::get_byte_size_from_header(addr);
126124
bool crosses_mapping = offset + size > (1 << section_shift);
127125
// Move the limit on use of the existing primary mapping.
@@ -135,27 +133,21 @@ char* Allocator::translate_less_critical(RefTranslation* ref_translation_ptr, re
135133
}
136134
if (REALM_LIKELY(!crosses_mapping)) {
137135
// Array fits inside primary mapping, no new mapping needed.
138-
#if REALM_ENABLE_ENCRYPTION
139-
realm::util::encryption_read_barrier(addr, size, txl.encrypted_mapping, nullptr);
140-
#endif
136+
util::encryption_read_barrier(addr, size, txl.encrypted_mapping);
141137
return addr;
142138
}
143-
else {
144-
// we need a cross-over mapping. If one is already established, use that.
145-
auto xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_acquire);
146-
if (!xover_mapping_addr) {
147-
// we need to establish a xover mapping - or wait for another thread to finish
148-
// establishing one:
149-
const_cast<Allocator*>(this)->get_or_add_xover_mapping(txl, idx, offset, size);
150-
// reload (can be relaxed since the call above synchronizes on a mutex)
151-
xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_relaxed);
152-
}
153-
// array is now known to be inside the established xover mapping:
154-
addr = xover_mapping_addr + (offset - txl.xover_mapping_base);
155-
#if REALM_ENABLE_ENCRYPTION
156-
realm::util::encryption_read_barrier(addr, size, txl.xover_encrypted_mapping, nullptr);
157-
#endif
158-
return addr;
139+
// we need a cross-over mapping. If one is already established, use that.
140+
auto xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_acquire);
141+
if (!xover_mapping_addr) {
142+
// we need to establish a xover mapping - or wait for another thread to finish
143+
// establishing one:
144+
const_cast<Allocator*>(this)->get_or_add_xover_mapping(txl, idx, offset, size);
145+
// reload (can be relaxed since the call above synchronizes on a mutex)
146+
xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_relaxed);
159147
}
148+
// array is now known to be inside the established xover mapping:
149+
addr = xover_mapping_addr + (offset - txl.xover_mapping_base);
150+
util::encryption_read_barrier(addr, size, txl.xover_encrypted_mapping);
151+
return addr;
160152
}
161153
} // namespace realm

src/realm/alloc.hpp

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class Allocator {
171171
// into equal chunks.
172172
struct RefTranslation {
173173
char* mapping_addr;
174-
uint64_t cookie;
174+
uint64_t cookie = 0x1234567890;
175175
std::atomic<size_t> lowest_possible_xover_offset = 0;
176176

177177
// member 'xover_mapping_addr' is used for memory synchronization of the fields
@@ -183,14 +183,12 @@ class Allocator {
183183
#if REALM_ENABLE_ENCRYPTION
184184
util::EncryptedFileMapping* encrypted_mapping = nullptr;
185185
util::EncryptedFileMapping* xover_encrypted_mapping = nullptr;
186+
#else
187+
static inline util::EncryptedFileMapping* const encrypted_mapping = nullptr;
188+
static inline util::EncryptedFileMapping* const xover_encrypted_mapping = nullptr;
186189
#endif
187-
explicit RefTranslation(char* addr)
190+
explicit RefTranslation(char* addr = nullptr)
188191
: mapping_addr(addr)
189-
, cookie(0x1234567890)
190-
{
191-
}
192-
RefTranslation()
193-
: RefTranslation(nullptr)
194192
{
195193
}
196194
~RefTranslation()
@@ -222,7 +220,7 @@ class Allocator {
222220
};
223221
// This pointer may be changed concurrently with access, so make sure it is
224222
// atomic!
225-
std::atomic<RefTranslation*> m_ref_translation_ptr;
223+
std::atomic<RefTranslation*> m_ref_translation_ptr{nullptr};
226224

227225
/// The specified size must be divisible by 8, and must not be
228226
/// zero.
@@ -252,7 +250,7 @@ class Allocator {
252250
char* translate_critical(RefTranslation*, ref_type ref) const noexcept;
253251
char* translate_less_critical(RefTranslation*, ref_type ref) const noexcept;
254252
virtual void get_or_add_xover_mapping(RefTranslation&, size_t, size_t, size_t) = 0;
255-
Allocator() noexcept;
253+
Allocator() noexcept = default;
256254
size_t get_section_index(size_t pos) const noexcept;
257255
inline size_t get_section_base(size_t index) const noexcept;
258256

@@ -271,11 +269,9 @@ class Allocator {
271269
// used to detect if the allocator (and owning structure, e.g. Table)
272270
// is recycled. Mismatch on this counter will cause accesors
273271
// lower in the hierarchy to throw if access is attempted.
274-
std::atomic<uint_fast64_t> m_content_versioning_counter;
275-
276-
std::atomic<uint_fast64_t> m_storage_versioning_counter;
277-
278-
std::atomic<uint_fast64_t> m_instance_versioning_counter;
272+
std::atomic<uint_fast64_t> m_content_versioning_counter{0};
273+
std::atomic<uint_fast64_t> m_storage_versioning_counter{0};
274+
std::atomic<uint_fast64_t> m_instance_versioning_counter{0};
279275

280276
inline uint_fast64_t get_storage_version(uint64_t instance_version)
281277
{
@@ -547,14 +543,6 @@ inline bool Allocator::is_read_only(ref_type ref) const noexcept
547543
return ref < m_baseline.load(std::memory_order_relaxed);
548544
}
549545

550-
inline Allocator::Allocator() noexcept
551-
{
552-
m_content_versioning_counter = 0;
553-
m_storage_versioning_counter = 0;
554-
m_instance_versioning_counter = 0;
555-
m_ref_translation_ptr = nullptr;
556-
}
557-
558546
// performance critical part of the translation process. Less critical code is in translate_less_critical.
559547
inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr, ref_type ref) const noexcept
560548
{
@@ -566,30 +554,23 @@ inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr,
566554
if (REALM_LIKELY(offset < lowest_possible_xover_offset)) {
567555
// the lowest possible xover offset may grow concurrently, but that will not affect this code path
568556
char* addr = txl.mapping_addr + offset;
569-
#if REALM_ENABLE_ENCRYPTION
570-
realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping,
571-
NodeHeader::get_byte_size_from_header);
572-
#endif
557+
util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping);
558+
size_t size = NodeHeader::get_byte_size_from_header(addr);
559+
util::encryption_read_barrier(addr, size, txl.encrypted_mapping);
573560
return addr;
574561
}
575-
else {
576-
// the lowest possible xover offset may grow concurrently, but that will be handled inside the call
577-
return translate_less_critical(ref_translation_ptr, ref);
578-
}
562+
// the lowest possible xover offset may grow concurrently, but that will be handled inside the call
563+
return translate_less_critical(ref_translation_ptr, ref);
579564
}
580565
realm::util::terminate("Invalid ref translation entry", __FILE__, __LINE__, txl.cookie, 0x1234567890, ref, idx);
581-
return nullptr;
582566
}
583567

584568
inline char* Allocator::translate(ref_type ref) const noexcept
585569
{
586-
auto ref_translation_ptr = m_ref_translation_ptr.load(std::memory_order_acquire);
587-
if (REALM_LIKELY(ref_translation_ptr)) {
588-
return translate_critical(ref_translation_ptr, ref);
589-
}
590-
else {
591-
return do_translate(ref);
570+
if (auto ptr = m_ref_translation_ptr.load(std::memory_order_acquire); REALM_LIKELY(ptr)) {
571+
return translate_critical(ptr, ref);
592572
}
573+
return do_translate(ref);
593574
}
594575

595576

0 commit comments

Comments
 (0)