diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5d6328c4c..5e5a32aa49e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ### Fixed * ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) -* None. +* Potential stack-use-after-scope issue on changesets integration with msvc-2019 and mpack code ([PR #6911](https://github.com/realm/realm-core/pull/6911)) ### Breaking changes * None. @@ -17,7 +17,7 @@ ----------- ### Internals -* None. +* REALM_[ATMU]SAN cmake flags no longer override compilation options and can be combined with Debug|RelWithDebInfo|etc. build types. Rel[ATMU]SAN build type shortcuts are now all slightly optimized debug-based builds with sanitizers. REALM_ASAN now works with msvc (2019/2022) builds. ([PR #6911](https://github.com/realm/realm-core/pull/6911)) ---------------------------------------------- diff --git a/Jenkinsfile b/Jenkinsfile index 9c4cf92a6d2..ea490b5f8fe 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -196,8 +196,6 @@ jobWrapper { buildAndroidArm64Debug : doAndroidBuildInDocker('arm64-v8a', 'Debug'), buildAndroidTestsArmeabi: doAndroidBuildInDocker('armeabi-v7a', 'Debug', TestAction.Build), buildEmscripten : doBuildEmscripten('Debug'), - threadSanitizer : doCheckSanity(buildOptions + [enableSync: true, sanitizeMode: 'thread']), - addressSanitizer : doCheckSanity(buildOptions + [enableSync: true, sanitizeMode: 'address']), ] if (releaseTesting) { extendedChecks = [ @@ -312,63 +310,6 @@ def doCheckInDocker(Map options = [:]) { } } -def doCheckSanity(Map options = [:]) { - def privileged = ''; - - def cmakeOptions = [ - CMAKE_BUILD_TYPE: options.buildType, - REALM_MAX_BPNODE_SIZE: options.maxBpNodeSize, - REALM_ENABLE_SYNC: options.enableSync, - ] - - if (options.sanitizeMode.contains('thread')) { - cmakeOptions << [ - REALM_TSAN: "ON", - ] - } - else if (options.sanitizeMode.contains('address')) { - privileged = '--privileged' - cmakeOptions << [ - REALM_ASAN: "ON", - ] - } - - def cmakeDefinitions = cmakeOptions.collect { k,v -> "-D$k=$v" }.join(' ') - - return { - rlmNode('docker') { - getArchive() - - def environment = environment() + [ - 'CC=clang', - 'CXX=clang++', - 'UNITTEST_XML=unit-test-report.xml', - "UNITTEST_SUITE_NAME=Linux-${options.buildType}", - "TSAN_OPTIONS=\"suppressions=${WORKSPACE}/test/tsan.suppress\"" - ] - buildDockerEnv('linux.Dockerfile').inside(privileged) { - withEnv(environment) { - try { - dir('build-dir') { - sh "cmake ${cmakeDefinitions} -G Ninja .." - runAndCollectWarnings( - script: 'ninja', - parser: "clang", - name: "linux-clang-${options.buildType}-${options.sanitizeMode}", - filters: warningFilters, - ) - sh "${ctest_cmd}" - } - - } finally { - junit testResults: 'build-dir/test/unit-test-report.xml' - } - } - } - } - } -} - def doBuildLinux(String buildType) { return { rlmNode('docker') { diff --git a/bindgen/src/realm_helpers.h b/bindgen/src/realm_helpers.h index 064c3a14c7c..2ac02b8cd10 100644 --- a/bindgen/src/realm_helpers.h +++ b/bindgen/src/realm_helpers.h @@ -221,8 +221,12 @@ struct Helpers { static void simulate_sync_error(SyncSession& session, const int& code, const std::string& message, const std::string& type, bool is_fatal) { - sync::SessionErrorInfo error(Status{type == "realm::sync::ProtocolError" ? ErrorCodes::SyncClientResetRequired : ErrorCodes::UnknownError, message}, sync::IsFatal(is_fatal)); - error.server_requests_action = code == 211 ? sync::ProtocolErrorInfo::Action::ClientReset : sync::ProtocolErrorInfo::Action::Warning; + sync::SessionErrorInfo error(Status{type == "realm::sync::ProtocolError" ? ErrorCodes::SyncClientResetRequired + : ErrorCodes::UnknownError, + message}, + sync::IsFatal(is_fatal)); + error.server_requests_action = + code == 211 ? sync::ProtocolErrorInfo::Action::ClientReset : sync::ProtocolErrorInfo::Action::Warning; SyncSession::OnlyForTesting::handle_error(session, std::move(error)); } diff --git a/evergreen/config.yml b/evergreen/config.yml index fd5fd21e90d..5e1c0f7ece5 100644 --- a/evergreen/config.yml +++ b/evergreen/config.yml @@ -1214,6 +1214,7 @@ buildvariants: cxx_compiler: "./clang_binaries/bin/clang++" run_with_encryption: On enable_tsan: On + cmake_build_type: RelWithDebInfo tasks: - name: core_tests_group distros: @@ -1232,6 +1233,7 @@ buildvariants: llvm_symbolizer: "./clang_binaries/bin/llvm-symbolizer" run_with_encryption: On enable_asan: On + cmake_build_type: RelWithDebInfo tasks: - name: core_tests_group distros: @@ -1269,6 +1271,7 @@ buildvariants: cmake_bindir: "./cmake_binaries/bin" fetch_missing_dependencies: On enable_asan: On + cmake_build_type: RelWithDebInfo c_compiler: "./clang_binaries/bin/clang" cxx_compiler: "./clang_binaries/bin/clang++" llvm_symbolizer: "./clang_binaries/bin/llvm-symbolizer" @@ -1287,6 +1290,7 @@ buildvariants: cmake_bindir: "./cmake_binaries/bin" fetch_missing_dependencies: On enable_tsan: On + cmake_build_type: RelWithDebInfo c_compiler: "./clang_binaries/bin/clang" cxx_compiler: "./clang_binaries/bin/clang++" tasks: @@ -1301,6 +1305,7 @@ buildvariants: cmake_bindir: "./cmake_binaries/bin" fetch_missing_dependencies: On enable_ubsan: On + cmake_build_type: RelWithDebInfo c_compiler: "./clang_binaries/bin/clang" cxx_compiler: "./clang_binaries/bin/clang++" tasks: @@ -1448,6 +1453,70 @@ buildvariants: - name: long-running-tests - name: swift-build-and-test +- name: macos-1100-x64-asan + display_name: "MacOS 11.0 x86_64 (ASAN)" + run_on: macos-1100 + expansions: + cmake_url: "https://s3.amazonaws.com/static.realm.io/evergreen-assets/cmake-3.20.3-macos-universal.tar.gz" + cmake_bindir: "./cmake_binaries/CMake.app/Contents/bin" + cmake_toolchain_file: "./tools/cmake/xcode.toolchain.cmake" + cmake_generator: Xcode + max_jobs: $(sysctl -n hw.logicalcpu) + xcode_developer_dir: /Applications/Xcode13.1.app/Contents/Developer + extra_flags: -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_OSX_ARCHITECTURES=x86_64 + cmake_build_type: RelWithDebInfo + enable_asan: On + tasks: + - name: compile_test + +- name: macos-1100-x64-tsan + display_name: "MacOS 11.0 x86_64 (TSAN)" + run_on: macos-1100 + expansions: + cmake_url: "https://s3.amazonaws.com/static.realm.io/evergreen-assets/cmake-3.20.3-macos-universal.tar.gz" + cmake_bindir: "./cmake_binaries/CMake.app/Contents/bin" + cmake_toolchain_file: "./tools/cmake/xcode.toolchain.cmake" + cmake_generator: Xcode + max_jobs: $(sysctl -n hw.logicalcpu) + xcode_developer_dir: /Applications/Xcode13.1.app/Contents/Developer + extra_flags: -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_OSX_ARCHITECTURES=x86_64 + cmake_build_type: RelWithDebInfo + enable_tsan: On + tasks: + - name: compile_test + +- name: macos-1100-arm64-asan + display_name: "MacOS 11 arm64 (ASAN)" + run_on: macos-1100-arm64 + expansions: + cmake_url: "https://s3.amazonaws.com/static.realm.io/evergreen-assets/cmake-3.20.3-macos-universal.tar.gz" + cmake_bindir: "./cmake_binaries/CMake.app/Contents/bin" + cmake_toolchain_file: "./tools/cmake/xcode.toolchain.cmake" + cmake_generator: Xcode + max_jobs: $(sysctl -n hw.logicalcpu) + xcode_developer_dir: /Applications/Xcode13.1.app/Contents/Developer + extra_flags: -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_OSX_ARCHITECTURES=arm64 + cmake_build_type: RelWithDebInfo + enable_asan: On + tasks: + - name: compile_test + +- name: macos-1100-arm64-tsan + display_name: "MacOS 11 arm64 (TSAN)" + run_on: macos-1100-arm64 + expansions: + cmake_url: "https://s3.amazonaws.com/static.realm.io/evergreen-assets/cmake-3.20.3-macos-universal.tar.gz" + cmake_bindir: "./cmake_binaries/CMake.app/Contents/bin" + cmake_toolchain_file: "./tools/cmake/xcode.toolchain.cmake" + cmake_generator: Xcode + max_jobs: $(sysctl -n hw.logicalcpu) + xcode_developer_dir: /Applications/Xcode13.1.app/Contents/Developer + extra_flags: -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_OSX_ARCHITECTURES=arm64 + cmake_build_type: RelWithDebInfo + enable_tsan: On + tasks: + - name: compile_test + - name: macos-coverage display_name: "MacOS 11 arm64 (Code Coverage)" run_on: macos-1100-arm64 @@ -1529,3 +1598,20 @@ buildvariants: python3: "/cygdrive/c/python/python37/python.exe" tasks: - name: compile_test + +- name: windows-64-vs2019-asan + display_name: "Windows x86_64 (VS 2019 ASAN)" + run_on: windows-vsCurrent-large + expansions: + cmake_url: "https://s3.amazonaws.com/static.realm.io/evergreen-assets/cmake-3.20.3-windows-x86_64.zip" + cmake_bindir: "./cmake-3.20.3-windows-x86_64/bin" + cmake_generator: "Visual Studio 16 2019" + extra_flags: "-A x64" + cmake_build_type: "Debug" + enable_asan: On + max_jobs: $(($(grep -c proc /proc/cpuinfo) / 2)) + fetch_missing_dependencies: On + curl_base: "/cygdrive/c/curl" + python3: "/cygdrive/c/python/python37/python.exe" + tasks: + - name: compile_test diff --git a/src/external/s2/CMakeLists.txt b/src/external/s2/CMakeLists.txt index 5e706985149..1b0a3f20d69 100644 --- a/src/external/s2/CMakeLists.txt +++ b/src/external/s2/CMakeLists.txt @@ -10,6 +10,7 @@ set(S2_SOURCES s1interval.cc s2cap.cc s2cell.cc + s2cellunion.cc s2edgeindex.cc s2edgeutil.cc s2latlngrect.cc diff --git a/src/realm/CMakeLists.txt b/src/realm/CMakeLists.txt index 03ae01356d1..73c96715631 100644 --- a/src/realm/CMakeLists.txt +++ b/src/realm/CMakeLists.txt @@ -306,7 +306,6 @@ set_target_properties(Storage PROPERTIES OUTPUT_NAME "realm" ) -target_compile_options(Storage PUBLIC ${REALM_SANITIZER_FLAGS}) if(REALM_USE_FAST_LINKER) target_link_options(Storage PUBLIC ${REALM_USE_FAST_LINKER}) endif() @@ -315,9 +314,12 @@ target_compile_definitions(Storage PUBLIC $<$:REALM_DEBUG=1> ) -if(NOT MSVC) +if (REALM_SANITIZER_FLAGS) target_compile_options(Storage PUBLIC ${REALM_SANITIZER_FLAGS}) - target_link_options(Storage PUBLIC ${REALM_SANITIZER_FLAGS}) + + if (REALM_SANITIZER_LINK_FLAGS) + target_link_options(Storage PUBLIC ${REALM_SANITIZER_LINK_FLAGS}) + endif() endif() target_include_directories(Storage INTERFACE diff --git a/src/realm/sync/noinst/client_history_impl.cpp b/src/realm/sync/noinst/client_history_impl.cpp index 13fb457e16b..d295eb8e6ee 100644 --- a/src/realm/sync/noinst/client_history_impl.cpp +++ b/src/realm/sync/noinst/client_history_impl.cpp @@ -1194,6 +1194,7 @@ void ClientHistory::update_from_ref_and_version(ref_type ref, version_type versi m_arrays->init_from_ref(ref); } else { + REALM_ASSERT_RELEASE(m_group); m_arrays.emplace(m_db->get_alloc(), *m_group, ref); } diff --git a/src/realm/sync/transform.cpp b/src/realm/sync/transform.cpp index 774abcc1321..322088c0ab2 100644 --- a/src/realm/sync/transform.cpp +++ b/src/realm/sync/transform.cpp @@ -997,16 +997,18 @@ struct MergeUtils { bool same_path_element(const Instruction::Path::Element& left, const Instruction::Path::Element& right) const noexcept { - const auto& pred = util::overload{ - [&](uint32_t lhs, uint32_t rhs) { + auto pred = util::overload{ + [](uint32_t lhs, uint32_t rhs) { return lhs == rhs; }, - [&](InternString lhs, InternString rhs) { + [this](InternString lhs, InternString rhs) { return same_string(lhs, rhs); }, - [&](const auto&, const auto&) { - // FIXME: Paths contain incompatible element types. Should we raise an - // error here? + // FIXME: Paths contain incompatible element types. Should we raise an error here? + [](InternString, uint32_t) { + return false; + }, + [](uint32_t, InternString) { return false; }, }; diff --git a/src/realm/table.hpp b/src/realm/table.hpp index 2a6d8b0c608..b1df78f058d 100644 --- a/src/realm/table.hpp +++ b/src/realm/table.hpp @@ -903,10 +903,10 @@ class ColKeyIterator { private: friend class ColKeys; - const Table* m_table; + ConstTableRef m_table; size_t m_pos; - ColKeyIterator(const Table* t, size_t p) + ColKeyIterator(const ConstTableRef& t, size_t p) : m_table(t) , m_pos(p) { @@ -915,8 +915,8 @@ class ColKeyIterator { class ColKeys { public: - ColKeys(const Table* t) - : m_table(t) + ColKeys(ConstTableRef&& t) + : m_table(std::move(t)) { } @@ -947,7 +947,7 @@ class ColKeys { } private: - const Table* m_table; + ConstTableRef m_table; }; // Class used to collect a chain of links when building up a Query following links. @@ -1079,7 +1079,7 @@ class LinkChain { inline ColKeys Table::get_column_keys() const { - return ColKeys(this); + return ColKeys(ConstTableRef(this, m_alloc.get_instance_version())); } inline uint_fast64_t Table::get_content_version() const noexcept diff --git a/src/realm/timestamp.hpp b/src/realm/timestamp.hpp index 28647f26fcf..5e77f2717fe 100644 --- a/src/realm/timestamp.hpp +++ b/src/realm/timestamp.hpp @@ -19,6 +19,7 @@ #ifndef REALM_TIMESTAMP_HPP #define REALM_TIMESTAMP_HPP +#include #include #include #include @@ -182,8 +183,7 @@ class Timestamp { return size_t(m_seconds) ^ size_t(m_nanoseconds); } - // Buffer must be at least 32 bytes long - const char* to_string(char* buffer) const; + const char* to_string(std::array& buffer) const; template friend std::basic_ostream& operator<<(std::basic_ostream& out, const Timestamp&); @@ -199,7 +199,7 @@ class Timestamp { template inline std::basic_ostream& operator<<(std::basic_ostream& out, const Timestamp& d) { - char buffer[32]; + std::array buffer{}; out << d.to_string(buffer); return out; } diff --git a/src/realm/util/logger.cpp b/src/realm/util/logger.cpp index a826f1d23e5..02edb494371 100644 --- a/src/realm/util/logger.cpp +++ b/src/realm/util/logger.cpp @@ -112,6 +112,8 @@ const std::string_view Logger::level_to_string(Level level) noexcept void StderrLogger::do_log(Level level, const std::string& message) { + static Mutex mutex; + LockGuard l(mutex); // std::cerr is unbuffered, so no need to flush std::cerr << get_level_prefix(level) << message << '\n'; // Throws } diff --git a/src/realm/util/serializer.cpp b/src/realm/util/serializer.cpp index 31e34b968dd..dbe23836d6a 100644 --- a/src/realm/util/serializer.cpp +++ b/src/realm/util/serializer.cpp @@ -74,7 +74,7 @@ static void out_dec(char** buffer, unsigned val, int width) static constexpr long epoc_julian_days = date_to_julian(1970, 1, 1); // 2440588 static constexpr int seconds_in_a_day = 24 * 60 * 60; -const char* Timestamp::to_string(char* buffer) const +const char* Timestamp::to_string(std::array& buffer) const { if (is_null()) { return "null"; @@ -105,7 +105,7 @@ const char* Timestamp::to_string(char* buffer) const julian_to_date(julian_days, &year, &month, &day); - char* p = buffer; + char* p = buffer.data(); if (year < 0) { *p++ = '-'; year = -year; @@ -123,9 +123,9 @@ const char* Timestamp::to_string(char* buffer) const out_dec(&p, secs, 2); *p = '\0'; if (nano) { - snprintf(p, 32 - (p - buffer), ".%09d", nano); + snprintf(p, 32 - (p - buffer.data()), ".%09d", nano); } - return buffer; + return buffer.data(); } namespace util { diff --git a/src/realm/util/timestamp_logger.cpp b/src/realm/util/timestamp_logger.cpp index 3be73875bb0..493546a054b 100644 --- a/src/realm/util/timestamp_logger.cpp +++ b/src/realm/util/timestamp_logger.cpp @@ -17,5 +17,7 @@ TimestampStderrLogger::TimestampStderrLogger(Config config, Level level) void TimestampStderrLogger::do_log(Logger::Level level, const std::string& message) { auto now = std::chrono::system_clock::now(); + static Mutex mutex; + LockGuard l(mutex); std::cerr << m_formatter.format(now) << ": " << get_level_prefix(level) << message << '\n'; // Throws } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f0c7acd4da7..dcc4e990352 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -129,7 +129,10 @@ set_source_files_properties(test_query_geo.cpp PROPERTIES # FIXME: Benchmarks if (MSVC) - append_source_file_compile_options(FILES test_query.cpp test_query_big.cpp FLAGS /bigobj) + append_source_file_compile_options( + FILES test_parser.cpp test_table.cpp test_query.cpp test_query_big.cpp + FLAGS /bigobj + ) endif() # Resources required for running the tests diff --git a/test/fuzz_tester.hpp b/test/fuzz_tester.hpp index a15a4de6f43..aa4f3ab6eef 100644 --- a/test/fuzz_tester.hpp +++ b/test/fuzz_tester.hpp @@ -909,8 +909,8 @@ void FuzzTester::round(unit_test::TestContext& test_context, std::string path std::cerr << trace_selected_link_list(client) << " = " << trace_selected_table(client) << "->get_object(" << row_key << ").get_linklist_ptr(" << col_key << ");\n"; } - client.selected_link_list = std::move(link_list); size_t num_links = link_list->size(); + client.selected_link_list = std::move(link_list); get_link_list_level_modify_actions(num_links, actions); } } diff --git a/test/object-store/audit.cpp b/test/object-store/audit.cpp index ec2173989d9..a219459a3b6 100644 --- a/test/object-store/audit.cpp +++ b/test/object-store/audit.cpp @@ -52,8 +52,11 @@ using namespace std::string_literals; using Catch::Matchers::StartsWith; using nlohmann::json; -#ifndef AUDIT_LOG_LEVEL -#define AUDIT_LOG_LEVEL util::Logger::Level::off +static auto audit_logger = +#ifdef AUDIT_LOG_LEVEL + std::make_shared(AUDIT_LOG_LEVEL); +#else + std::make_shared(); #endif namespace { @@ -299,8 +302,7 @@ TEST_CASE("audit object serialization", "[sync][pbs][audit]") { config.audit_config = std::make_shared(); auto serializer = std::make_shared(); config.audit_config->serializer = serializer; - config.audit_config->logger = std::make_shared(util::Logger::get_default_logger()); - config.audit_config->logger->set_level_threshold(AUDIT_LOG_LEVEL); + config.audit_config->logger = audit_logger; auto realm = Realm::get_shared_realm(config); auto audit = realm->audit_context(); REQUIRE(audit); @@ -1370,10 +1372,11 @@ TEST_CASE("audit management", "[sync][pbs][audit]") { SECTION("custom audit event") { // Verify that each of the completion handlers is called in the expected order std::atomic completions = 0; + std::array, 5> completion_results; auto expect_completion = [&](size_t expected) { - return [&completions, expected](std::exception_ptr e) { - REQUIRE_FALSE(e); - REQUIRE(completions++ == expected); + return [&, expected](std::exception_ptr e) { + completion_results[expected].second = bool(e); + completion_results[expected].first = completions++; }; }; @@ -1389,6 +1392,11 @@ TEST_CASE("audit management", "[sync][pbs][audit]") { return completions == 5; }); + for (size_t i = 0; i < 5; ++i) { + REQUIRE(i == completion_results[i].first); + REQUIRE_FALSE(completion_results[i].second); + } + auto events = get_audit_events(test_session, false); REQUIRE(events.size() == 4); REQUIRE(events[0].activity == "event 1"); @@ -1486,9 +1494,7 @@ TEST_CASE("audit realm sharding", "[sync][pbs][audit]") { {"object", {{"_id", PropertyType::Int, Property::IsPrimary{true}}, {"value", PropertyType::Int}}}, }; config.audit_config = std::make_shared(); - auto logger = std::make_shared(util::Logger::get_default_logger()); - logger->set_level_threshold(AUDIT_LOG_LEVEL); - config.audit_config->logger = logger; + config.audit_config->logger = audit_logger; auto realm = Realm::get_shared_realm(config); auto audit = realm->audit_context(); REQUIRE(audit); @@ -1591,7 +1597,7 @@ TEST_CASE("audit realm sharding", "[sync][pbs][audit]") { // Open a different Realm with the same user and audit prefix SyncTestFile config(test_session.app(), "other"); config.audit_config = std::make_shared(); - config.audit_config->logger = logger; + config.audit_config->logger = audit_logger; auto realm = Realm::get_shared_realm(config); auto audit2 = realm->audit_context(); REQUIRE(audit2); @@ -1618,7 +1624,7 @@ TEST_CASE("audit realm sharding", "[sync][pbs][audit]") { // Open the same Realm with a different audit prefix SyncTestFile config(test_session.app(), "parent"); config.audit_config = std::make_shared(); - config.audit_config->logger = logger; + config.audit_config->logger = audit_logger; config.audit_config->partition_value_prefix = "other"; auto realm = Realm::get_shared_realm(config); auto audit2 = realm->audit_context(); @@ -1675,8 +1681,7 @@ TEST_CASE("audit integration tests", "[sync][pbs][audit][baas]") { SyncTestFile config(session.app()->current_user(), bson::Bson("default")); config.schema = schema; config.audit_config = std::make_shared(); - config.audit_config->logger = std::make_shared(util::Logger::get_default_logger()); - config.audit_config->logger->set_level_threshold(AUDIT_LOG_LEVEL); + config.audit_config->logger = audit_logger; auto expect_error = [&](auto&& config, auto&& fn) -> SyncError { std::mutex mutex; diff --git a/test/object-store/migrations.cpp b/test/object-store/migrations.cpp index a9683d2a876..e6c34a7747a 100644 --- a/test/object-store/migrations.cpp +++ b/test/object-store/migrations.cpp @@ -2324,6 +2324,8 @@ TEST_CASE("migration: Additive", "[migration]") { REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]); REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]); + ColKey k0 = col_keys[0], k1 = col_keys[1]; + // Close and re-open the file entirely so that the coordinator is recreated realm.reset(); realm2.reset(); @@ -2331,8 +2333,8 @@ TEST_CASE("migration: Additive", "[migration]") { realm = Realm::get_shared_realm(config); REQUIRE(realm->schema() == schema); - REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]); - REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]); + REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == k0); + REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == k1); } SECTION("obtaining a frozen Realm from before an external schema change") { diff --git a/test/object-store/realm.cpp b/test/object-store/realm.cpp index c52f8732029..343051c0b1f 100644 --- a/test/object-store/realm.cpp +++ b/test/object-store/realm.cpp @@ -1070,18 +1070,18 @@ TEST_CASE("Get Realm using Async Open", "[sync][pbs][async open]") { progress_notifier2_called = true; }); task->start([&](ThreadSafeReference realm_ref, std::exception_ptr err) { - REQUIRE(!err); - SharedRealm realm = Realm::get_shared_realm(std::move(realm_ref)); - REQUIRE(realm); std::lock_guard guard(mutex); + REQUIRE(!err); + REQUIRE(realm_ref); task1_completed = true; }); task->cancel(); + ThreadSafeReference rref; task2->start([&](ThreadSafeReference realm_ref, std::exception_ptr err) { - REQUIRE(!err); - SharedRealm realm = Realm::get_shared_realm(std::move(realm_ref)); - REQUIRE(realm); std::lock_guard guard(mutex); + REQUIRE(!err); + REQUIRE(realm_ref); + rref = std::move(realm_ref); task2_completed = true; }); write = nullptr; // unblock sync @@ -1094,6 +1094,8 @@ TEST_CASE("Get Realm using Async Open", "[sync][pbs][async open]") { REQUIRE(!task1_completed); REQUIRE(progress_notifier2_called); REQUIRE(task2_completed); + SharedRealm realm = Realm::get_shared_realm(std::move(rref)); + REQUIRE(realm); } SECTION("downloads latest state for Realms which already exist locally") { diff --git a/test/object-store/sync/flx_migration.cpp b/test/object-store/sync/flx_migration.cpp index 31aa9878dce..7452b4b2619 100644 --- a/test/object-store/sync/flx_migration.cpp +++ b/test/object-store/sync/flx_migration.cpp @@ -840,7 +840,7 @@ TEST_CASE("Async open + client reset", "[sync][flx][flx migration][baas]") { REQUIRE(before); auto table_before = before->read_group().get_table("class_Object"); CHECK(table_before); - SharedRealm after = Realm::get_shared_realm(std::move(after_ref), util::Scheduler::make_default()); + SharedRealm after = Realm::get_shared_realm(std::move(after_ref), util::Scheduler::make_dummy()); REQUIRE(after); auto table_after = after->read_group().get_table("class_Object"); REQUIRE(table_after); diff --git a/test/object-store/util/sync/sync_test_utils.cpp b/test/object-store/util/sync/sync_test_utils.cpp index 58b739dc204..e61775e68f2 100644 --- a/test/object-store/util/sync/sync_test_utils.cpp +++ b/test/object-store/util/sync/sync_test_utils.cpp @@ -266,16 +266,20 @@ void async_open_realm(const Realm::Config& config, std::mutex mutex; bool did_finish = false; auto task = Realm::get_synchronized_realm(config); - task->start([&, callback = std::move(finish)](ThreadSafeReference&& ref, std::exception_ptr e) { - callback(std::move(ref), e); + ThreadSafeReference tsr; + std::exception_ptr err = nullptr; + task->start([&](ThreadSafeReference&& ref, std::exception_ptr e) { std::lock_guard lock(mutex); did_finish = true; + tsr = std::move(ref); + err = e; }); util::EventLoop::main().run_until([&] { std::lock_guard lock(mutex); return did_finish; }); task->cancel(); // don't run the above notifier again on this session + finish(std::move(tsr), err); } #endif // REALM_ENABLE_AUTH_TESTS diff --git a/test/test_json.cpp b/test/test_json.cpp index a43bf7f7b9c..16b83ca7aa8 100644 --- a/test/test_json.cpp +++ b/test/test_json.cpp @@ -865,16 +865,16 @@ using namespace std::chrono; TEST(Json_Timestamp) { - char buffer1[31]; - char buffer2[31]; + std::array buffer1{}; + std::array buffer2{}; Timestamp(-63549305085, 0).to_string(buffer1); - CHECK(strcmp(buffer1, "-0044-03-15 15:15:15") == 0); + CHECK(strcmp(buffer1.data(), "-0044-03-15 15:15:15") == 0); Timestamp(0, 0).to_string(buffer1); - CHECK(strcmp(buffer1, "1970-01-01 00:00:00") == 0); + CHECK(strcmp(buffer1.data(), "1970-01-01 00:00:00") == 0); Timestamp(-1, 0).to_string(buffer1); - CHECK(strcmp(buffer1, "1969-12-31 23:59:59") == 0); + CHECK(strcmp(buffer1.data(), "1969-12-31 23:59:59") == 0); Timestamp(-1, -100000000).to_string(buffer1); - CHECK(strcmp(buffer1, "1969-12-31 23:59:58.900000000") == 0); + CHECK(strcmp(buffer1.data(), "1969-12-31 23:59:58.900000000") == 0); // Compare our own to_string with standard implementation // for years 1900 to 2050 @@ -895,8 +895,8 @@ TEST(Json_Timestamp) #else gmtime_r(&seconds, &buf); #endif - strftime(buffer2, sizeof(buffer2), "%Y-%m-%d %H:%M:%S", &buf); - CHECK(strcmp(buffer1, buffer2) == 0); + strftime(buffer2.data(), sizeof(buffer2), "%Y-%m-%d %H:%M:%S", &buf); + CHECK(strcmp(buffer1.data(), buffer2.data()) == 0); } /* auto t1 = steady_clock::now(); diff --git a/test/test_table.cpp b/test/test_table.cpp index aea5a30fc00..37874af43c1 100644 --- a/test/test_table.cpp +++ b/test/test_table.cpp @@ -3401,7 +3401,7 @@ TEST(Table_object_by_index) } // String query benchmark -TEST(Table_QuickSort2) +NONCONCURRENT_TEST(Table_QuickSort2) { Table ttt; auto strings = ttt.add_column(type_String, "2"); @@ -4007,7 +4007,7 @@ TEST(Table_PrimaryKeyIndexBug) CHECK_EQUAL(cnt, 1); } -TEST(Table_PrimaryKeyString) +NONCONCURRENT_TEST(Table_PrimaryKeyString) { #ifdef REALM_DEBUG int nb_rows = 1000; diff --git a/test/util/unit_test.cpp b/test/util/unit_test.cpp index e24e782b688..c0244df6c6e 100644 --- a/test/util/unit_test.cpp +++ b/test/util/unit_test.cpp @@ -512,22 +512,21 @@ bool TestList::run(Config config) if (config.num_threads < 1) throw std::runtime_error("Bad number of threads"); - std::shared_ptr root_logger; + std::shared_ptr shared_logger; if (config.logger) { - root_logger = config.logger; + shared_logger = config.logger; } else { if (config.log_timestamps) { util::TimestampStderrLogger::Config config; config.precision = util::TimestampStderrLogger::Precision::milliseconds; config.format = "%FT%T"; - root_logger = std::make_shared(std::move(config)); // Throws + shared_logger = std::make_shared(std::move(config)); // Throws } else { - root_logger = util::Logger::get_default_logger(); // Throws + shared_logger = util::Logger::get_default_logger(); // Throws } } - std::shared_ptr shared_logger = std::make_shared(root_logger); Reporter fallback_reporter; Reporter& reporter = config.reporter ? *config.reporter : fallback_reporter; diff --git a/test/util/unit_test.hpp b/test/util/unit_test.hpp index f637f297fb1..75bf3f7bcfd 100644 --- a/test/util/unit_test.hpp +++ b/test/util/unit_test.hpp @@ -200,7 +200,7 @@ static const bool running_with_asan = false; // android doesn't implement posix_spawn(), iOS doesn't permit starting another process constexpr bool testing_supports_spawn_process = false; #else -constexpr bool testing_supports_spawn_process = !running_with_valgrind && !running_with_tsan && !running_with_asan; +constexpr bool testing_supports_spawn_process = !running_with_valgrind; #endif //@{ diff --git a/tools/cmake/SpecialtyBuilds.cmake b/tools/cmake/SpecialtyBuilds.cmake index 938bf0cdc32..4d1a3eb49b3 100644 --- a/tools/cmake/SpecialtyBuilds.cmake +++ b/tools/cmake/SpecialtyBuilds.cmake @@ -1,16 +1,21 @@ if (CMAKE_BUILD_TYPE MATCHES "RelAssert") set(REALM_ENABLE_ASSERTIONS ON CACHE BOOL "Build with assertions") - set(CMAKE_CXX_FLAGS_RELASSERT ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) endif() if (CMAKE_BUILD_TYPE MATCHES "RelASAN") set(REALM_ASAN ON CACHE BOOL "Build with address sanitizer") - set(CMAKE_CXX_FLAGS_RELASAN "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O1") endif() if (CMAKE_BUILD_TYPE MATCHES "RelTSAN") set(REALM_TSAN ON CACHE BOOL "Build with address sanitizer") - set(CMAKE_CXX_FLAGS_RELTSAN "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O1") +endif() + +if (CMAKE_BUILD_TYPE MATCHES "RelMSAN") + set(REALM_MSAN ON CACHE BOOL "Build with memory sanitizer") +endif() + +if (CMAKE_BUILD_TYPE MATCHES "RelUSAN") + set(REALM_USAN ON CACHE BOOL "Build with undefined sanitizer") endif() # ------------- @@ -79,12 +84,20 @@ endif() # ------------- option(REALM_ASAN "Compile with address sanitizer support" OFF) if(REALM_ASAN) - if(MSVC) - message(FATAL_ERROR - "The Address Sanitizer is not yet supported on Visual Studio builds") + if (MSVC) + set(REALM_SANITIZER_FLAGS /fsanitize=address) + set(REALM_SANITIZER_LINK_FLAGS /INCREMENTAL:NO) + + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelASAN") + list(APPEND REALM_SANITIZER_FLAGS /Ox /Zi) + list(APPEND REALM_SANITIZER_LINK_FLAGS /DEBUG) + elseif (NOT "${CMAKE_BUILD_TYPE}" MATCHES ".*Deb.*") + # disable warning for better stacktrace for asan + # pdbs can be activated with RelWithDebInfo or RelASAN + list(APPEND REALM_SANITIZER_FLAGS /wd5072) + endif() else() - list(APPEND REALM_SANITIZER_FLAGS -fsanitize=address -fno-sanitize-recover=all -fsanitize-address-use-after-scope) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -g") + set(REALM_SANITIZER_FLAGS -fsanitize=address -fno-sanitize-recover=all -fsanitize-address-use-after-scope -fno-omit-frame-pointer) endif() endif() @@ -97,13 +110,7 @@ if(REALM_TSAN) message(FATAL_ERROR "The Thread Sanitizer is not yet supported on Visual Studio builds") else() - list(APPEND REALM_SANITIZER_FLAGS -fsanitize=thread -fno-sanitize-recover=all) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -g -fPIE") - # According to the clang docs, if -fsanitize=thread is specified then compiling - # and linking with PIE is turned on automatically. - if (CMAKE_COMPILER_IS_GNUXX) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") - endif() + set(REALM_SANITIZER_FLAGS -fsanitize=thread -fno-sanitize-recover=all -fno-omit-frame-pointer) endif() endif() @@ -116,8 +123,7 @@ if(REALM_MSAN) message(FATAL_ERROR "The Memory Sanitizer is not yet supported on Visual Studio builds") else() - list(APPEND REALM_SANITIZER_FLAGS -fsanitize=memory -fsanitize-memory-track-origins) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -O2 -g -fPIE -pie") + set(REALM_SANITIZER_FLAGS -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer) endif() endif() @@ -130,7 +136,29 @@ if(REALM_USAN) message(FATAL_ERROR "The Undefined Sanitizer is not yet supported on Visual Studio builds") else() - list(APPEND REALM_SANITIZER_FLAGS -fsanitize=undefined -fno-sanitize-recover=all) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -O2 -g -fPIE -pie") + set(REALM_SANITIZER_FLAGS -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer) + endif() +endif() + +if (REALM_SANITIZER_FLAGS) + if (NOT MSVC) + if ("${CMAKE_BUILD_TYPE}" MATCHES "Rel[ATMU]SAN") + list(APPEND REALM_SANITIZER_FLAGS -O1 -g) + endif() + + set(REALM_SANITIZER_LINK_FLAGS ${REALM_SANITIZER_FLAGS}) + + if (CMAKE_COMPILER_IS_GNUXX) # activated for clang automatically according to docs + list(APPEND REALM_SANITIZER_LINK_FLAGS -pie) + endif() + endif() + + add_compile_options(${REALM_SANITIZER_FLAGS}) + if (MSVC) + add_compile_definitions(_DISABLE_STRING_ANNOTATION _DISABLE_VECTOR_ANNOTATION) + endif() + + if (REALM_SANITIZER_LINK_FLAGS) + add_link_options(${REALM_SANITIZER_LINK_FLAGS}) endif() endif()