diff --git a/CHANGELOG.md b/CHANGELOG.md index 947d4fb053..dd40e1a8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Fix crash during client app shutdown when Logger log level is set higher than Info. ([#7969](https://github.com/realm/realm-core/issues/7969), since v13.23.3) * If File::rw_lock() fails to open a file the exception message does not contain the filename ([#7999](https://github.com/realm/realm-core/issues/7999), since v6.0.21) * Fallback to hashed filename will fail if length of basename is between 240 and 250 ([#8007](https://github.com/realm/realm-core/issues/8007), since v10.0.0) +* Swift API misuse within a callback from core would result in an internal unreachable error rather than the exception being propagated properly ([#7836](https://github.com/realm/realm-core/issues/7836)). ### Breaking changes * None. diff --git a/Package.swift b/Package.swift index efcd53cf67..bbd07e429a 100644 --- a/Package.swift +++ b/Package.swift @@ -73,6 +73,7 @@ let notSyncServerSources: [String] = [ "realm/disable_sync_to_disk.cpp", "realm/error_codes.cpp", "realm/exceptions.cpp", + "realm/exceptions.mm", "realm/geospatial.cpp", "realm/global_key.cpp", "realm/group.cpp", diff --git a/src/realm/CMakeLists.txt b/src/realm/CMakeLists.txt index b5aebd5d3b..3cb6304a03 100644 --- a/src/realm/CMakeLists.txt +++ b/src/realm/CMakeLists.txt @@ -291,6 +291,10 @@ if(NOT MSVC) list(APPEND REALM_SOURCES util/interprocess_mutex.cpp) endif() +if(APPLE) + list(APPEND REALM_SOURCES exceptions.mm) +endif() + if (REALM_ENABLE_GEOSPATIAL) list(APPEND REALM_SOURCES geospatial.cpp) list(APPEND REALM_INSTALL_HEADERS geospatial.hpp) diff --git a/src/realm/exceptions.cpp b/src/realm/exceptions.cpp index 966572fe3f..acb476aa8a 100644 --- a/src/realm/exceptions.cpp +++ b/src/realm/exceptions.cpp @@ -64,6 +64,8 @@ Exception::Exception(Status status) { } +// Apple implementation in exceptions.mm +#if !REALM_PLATFORM_APPLE Status exception_to_status() noexcept { try { @@ -80,6 +82,7 @@ Status exception_to_status() noexcept REALM_UNREACHABLE(); } } +#endif // !REALM_PLATFORM_APPLE UnsupportedFileFormatVersion::UnsupportedFileFormatVersion(int version) : Exception(ErrorCodes::UnsupportedFileFormatVersion, diff --git a/src/realm/exceptions.mm b/src/realm/exceptions.mm new file mode 100644 index 0000000000..821cb0ea32 --- /dev/null +++ b/src/realm/exceptions.mm @@ -0,0 +1,45 @@ +/************************************************************************* + * + * Copyright 2024 Realm Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + **************************************************************************/ + +#include + +#include + +#include + +namespace realm { +Status exception_to_status() noexcept +{ + try { + throw; + } + catch (NSException* e) { + return Status(ErrorCodes::UnknownError, e.reason.UTF8String); + } + catch (const Exception& e) { + return e.to_status(); + } + catch (const std::exception& e) { + return Status(ErrorCodes::UnknownError, + util::format("Caught std::exception of type %1: %2", util::get_type_name(e), e.what())); + } + catch (...) { + REALM_UNREACHABLE(); + } +} +} // namespace realm diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 97829133ec..ed8b7bb78d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -113,6 +113,10 @@ if (REALM_ENABLE_GEOSPATIAL) list(APPEND CORE_TEST_SOURCES test_query_geo.cpp) endif() +if (APPLE) + list(APPEND CORE_TEST_SOURCES test_nsexception.mm) +endif() + set(LARGE_TEST_SOURCES large_tests/test_column_large.cpp large_tests/test_strings.cpp) diff --git a/test/test_nsexception.mm b/test/test_nsexception.mm new file mode 100644 index 0000000000..2a425a8e83 --- /dev/null +++ b/test/test_nsexception.mm @@ -0,0 +1,39 @@ +/************************************************************************* + * + * Copyright 2024 Realm Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + **************************************************************************/ + +#include "test.hpp" + +#include "realm/status.hpp" + +#include + +namespace realm { +namespace { +TEST(Status_NSException) +{ + try { + @throw [NSException exceptionWithName:@"Exception Name" reason:@"Expected reason" userInfo:nil]; + } + catch (...) { + auto status = exception_to_status(); + CHECK_EQUAL(status.code(), ErrorCodes::UnknownError); + CHECK_EQUAL(status.reason(), "Expected reason"); + } +} +} // namespace +} // namespace realm