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

realm / realm-core / 1681

18 Sep 2023 05:17PM UTC coverage: 91.188% (-0.002%) from 91.19%
1681

push

Evergreen

web-flow
Merge pull request #6886 from realm/blagoev/custom-v13.17.1

fix ErrorStorage creation

96050 of 175988 branches covered (0.0%)

0 of 2 new or added lines in 1 file covered. (0.0%)

87 existing lines in 14 files now uncovered.

233742 of 256330 relevant lines covered (91.19%)

6414053.02 hits per line

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

73.22
/src/realm/object-store/c_api/error.cpp
1
#include <realm/object-store/c_api/error.hpp>
2
#include <realm/object-store/c_api/util.hpp>
3
#include <realm/parser/query_parser.hpp>
4

5
#if REALM_PLATFORM_APPLE && !defined(RLM_NO_THREAD_LOCAL)
6
#define RLM_NO_THREAD_LOCAL
7
#endif
8

9
#if defined(RLM_NO_THREAD_LOCAL)
10
#include <pthread.h>
11
#endif
12

13
namespace realm::c_api {
14

15
ErrorStorage::ErrorStorage(std::exception_ptr ptr) noexcept
16
    : m_err(none)
17
    , m_message_buf()
18
    , m_usercode_error(nullptr)
19
{
2✔
20
    assign(std::move(ptr));
2✔
21
}
2✔
22

23
ErrorStorage::ErrorStorage(const ErrorStorage& other)
24
    : m_err(other.m_err)
25
    , m_message_buf(other.m_message_buf)
26
    , m_usercode_error(other.m_usercode_error)
27
{
6✔
28
    if (m_err) {
6✔
29
        m_err->message = m_message_buf.c_str();
6✔
30
    }
6✔
31
}
6✔
32

33
ErrorStorage& ErrorStorage::operator=(const ErrorStorage& other)
34
{
×
35
    m_err = other.m_err;
×
36
    m_message_buf = other.m_message_buf;
×
NEW
37
    m_usercode_error = other.m_usercode_error;
×
38
    if (m_err) {
×
39
        m_err->message = m_message_buf.c_str();
×
40
    }
×
41
    return *this;
×
42
}
×
43

44
ErrorStorage::ErrorStorage(ErrorStorage&& other)
45
    : m_err(std::move(other.m_err))
46
    , m_message_buf(std::move(other.m_message_buf))
47
    , m_usercode_error(std::move(other.m_usercode_error))
48
{
×
49
    if (m_err) {
×
50
        m_err->message = m_message_buf.c_str();
×
51
    }
×
52
    other.m_err.reset();
×
53
}
×
54

55
ErrorStorage& ErrorStorage::operator=(ErrorStorage&& other)
56
{
×
57
    m_err = std::move(other.m_err);
×
58
    m_message_buf = std::move(other.m_message_buf);
×
NEW
59
    m_usercode_error = std::move(other.m_usercode_error);
×
60
    if (m_err) {
×
61
        m_err->message = m_message_buf.c_str();
×
62
    }
×
63
    other.m_err.reset();
×
64
    return *this;
×
65
}
×
66

67
bool ErrorStorage::operator==(const ErrorStorage& other) const noexcept
68
{
2✔
69
    if (bool(m_err) != bool(other.m_err)) {
2✔
70
        return false;
×
71
    }
×
72
    else if (!m_err && !other.m_err) {
2!
73
        return true;
×
74
    }
×
75
    return m_err->error == other.m_err->error && m_message_buf == other.m_message_buf;
2✔
76
}
2✔
77

78
void ErrorStorage::assign(std::exception_ptr eptr) noexcept
79
{
194✔
80
    if (!eptr) {
194✔
81
        clear();
×
82
        return;
×
83
    }
×
84

97✔
85
    m_err.emplace();
194✔
86
    m_err->usercode_error = nullptr;
194✔
87
    m_err->path = nullptr;
194✔
88
    auto populate_error = [&](const std::exception& ex, ErrorCodes::Error error_code) {
194✔
89
        m_err->error = realm_errno_e(error_code);
194✔
90
        m_err->categories = ErrorCodes::error_categories(error_code).value();
194✔
91
        try {
194✔
92
            m_message_buf = ex.what();
194✔
93
            m_err->message = m_message_buf.c_str();
194✔
94
        }
194✔
95
        catch (const std::bad_alloc&) {
97✔
96
            // If we are unable to build the new error because we ran out of memory we should propagate the OOM
97
            // condition and leaf the m_message_buf as it was.
98
            m_err->error = RLM_ERR_OUT_OF_MEMORY;
×
99
            m_err->message = "Out of memory while creating realm_error_t";
×
100
        }
×
101
    };
194✔
102

97✔
103
    try {
194✔
104
        std::rethrow_exception(eptr);
194✔
105
    }
194✔
106

93✔
107
    // Core exceptions:
93✔
108
    catch (const Exception& ex) {
186✔
109
        populate_error(ex, ex.code());
186✔
110
        if (ex.code() == ErrorCodes::CallbackFailed) {
186✔
111
            m_err->usercode_error = static_cast<const CallbackFailed&>(ex).usercode_error;
6✔
112
        }
6✔
113
        if (ErrorCodes::error_categories(ex.code()).test(ErrorCategory::file_access)) {
186✔
114
            auto& file_access_error = static_cast<const FileAccessError&>(ex);
6✔
115
            m_path_buf = file_access_error.get_path();
6✔
116
            m_err->path = m_path_buf.c_str();
6✔
117
        }
6✔
118
    }
186✔
119

97✔
120
    // Generic exceptions:
97✔
121
    catch (const std::invalid_argument& ex) {
97✔
122
        populate_error(ex, ErrorCodes::InvalidArgument);
×
123
    }
×
124
    catch (const std::out_of_range& ex) {
97✔
125
        populate_error(ex, ErrorCodes::OutOfBounds);
×
126
    }
×
127
    catch (const std::logic_error& ex) {
97✔
128
        populate_error(ex, ErrorCodes::LogicError);
×
129
    }
×
130
    catch (const std::runtime_error& ex) {
101✔
131
        populate_error(ex, ErrorCodes::RuntimeError);
8✔
132
    }
8✔
133
    catch (const std::bad_alloc& ex) {
97✔
134
        populate_error(ex, ErrorCodes::OutOfMemory);
×
135
    }
×
136
    catch (const std::exception& ex) {
97✔
137
        populate_error(ex, ErrorCodes::UnknownError);
×
138
    }
×
139
    // FIXME: Handle more exception types.
97✔
140
    catch (...) {
97✔
141
        m_err->error = RLM_ERR_UNKNOWN;
×
142
        m_message_buf = "Unknown error";
×
143
        m_err->message = m_message_buf.c_str();
×
144
    }
×
145
}
194✔
146

147
bool ErrorStorage::has_error() const noexcept
148
{
8✔
149
    return static_cast<bool>(m_err);
8✔
150
}
8✔
151

152
bool ErrorStorage::get_as_realm_error_t(realm_error_t* out) const noexcept
153
{
246✔
154
    if (!m_err) {
246✔
155
        return false;
62✔
156
    }
62✔
157

92✔
158
    if (out) {
184✔
159
        *out = *m_err;
184✔
160
    }
184✔
161
    return true;
184✔
162
}
184✔
163

164
bool ErrorStorage::clear() noexcept
165
{
190✔
166
    auto ret = static_cast<bool>(m_err);
190✔
167
    m_err.reset();
190✔
168
    return ret;
190✔
169
}
190✔
170

171
void ErrorStorage::set_usercode_error(void* usercode_error)
172
{
2✔
173
    m_usercode_error = usercode_error;
2✔
174
}
2✔
175

176
void* ErrorStorage::get_and_clear_usercode_error()
177
{
10✔
178
    auto ret = m_usercode_error;
10✔
179
    m_usercode_error = nullptr;
10✔
180
    return ret;
10✔
181
}
10✔
182

183
ErrorStorage* ErrorStorage::get_thread_local()
184
{
644✔
185
#if !defined(RLM_NO_THREAD_LOCAL)
322✔
186
    static thread_local ErrorStorage g_error_storage;
322✔
187
    return &g_error_storage;
322✔
188
#else
189
    static pthread_key_t g_last_exception_key;
322✔
190
    static pthread_once_t g_last_exception_key_init_once = PTHREAD_ONCE_INIT;
322✔
191

192
    pthread_once(&g_last_exception_key_init_once, [] {
1✔
193
        pthread_key_create(&g_last_exception_key, [](void* ptr) {
1✔
194
            delete reinterpret_cast<ErrorStorage*>(ptr);
1✔
195
        });
1✔
196
    });
1✔
197

198
    if (auto ptr = reinterpret_cast<ErrorStorage*>(pthread_getspecific(g_last_exception_key)); ptr != nullptr) {
322✔
199
        return ptr;
320✔
200
    }
320✔
201

202
    auto ptr = new ErrorStorage{};
2✔
203
    pthread_setspecific(g_last_exception_key, ptr);
2✔
204
    return ptr;
2✔
205
#endif
2✔
206
}
324✔
207

208
void set_last_exception(std::exception_ptr eptr)
209
{
192✔
210
    ErrorStorage::get_thread_local()->assign(std::move(eptr));
192✔
211
}
192✔
212

213
RLM_API bool realm_get_last_error(realm_error_t* err)
214
{
238✔
215
    return ErrorStorage::get_thread_local()->get_as_realm_error_t(err);
238✔
216
}
238✔
217

218
RLM_API bool realm_clear_last_error()
219
{
190✔
220
    return ErrorStorage::get_thread_local()->clear();
190✔
221
}
190✔
222

223
RLM_API realm_async_error_t* realm_get_last_error_as_async_error(void)
224
{
8✔
225
    if (!ErrorStorage::get_thread_local()->has_error()) {
8✔
226
        return nullptr;
4✔
227
    }
4✔
228

2✔
229
    return new realm_async_error_t{*ErrorStorage::get_thread_local()};
4✔
230
}
4✔
231

232
RLM_API bool realm_get_async_error(const realm_async_error_t* async_err, realm_error_t* out_err)
233
{
14✔
234
    if (!async_err)
14✔
235
        return false;
6✔
236

4✔
237
    return async_err->error_storage.get_as_realm_error_t(out_err);
8✔
238
}
8✔
239

240
} // namespace realm::c_api
241

242
RLM_EXPORT bool realm_wrap_exceptions(void (*func)()) noexcept
243
{
8✔
244
    return realm::c_api::wrap_err([=]() {
8✔
245
        (func)();
8✔
246
        return true;
8✔
247
    });
8✔
248
}
8✔
249

250
RLM_API void realm_register_user_code_callback_error(void* usercode_error) noexcept
251
{
2✔
252
    realm::c_api::ErrorStorage::get_thread_local()->set_usercode_error(usercode_error);
2✔
253
}
2✔
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

© 2025 Coveralls, Inc