Skip to content

Commit d4742ea

Browse files
committed
Add exception guard around APM callback invocations
1 parent 2e1d88c commit d4742ea

File tree

1 file changed

+27
-12
lines changed
  • src/mongocxx/options/private

1 file changed

+27
-12
lines changed

src/mongocxx/options/private/apm.hh

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#pragma once
1616

17+
#include <iostream>
18+
1719
#include <mongocxx/options/apm.hpp>
1820
#include <mongocxx/private/libmongoc.hh>
1921

@@ -26,76 +28,89 @@ namespace options {
2628
using apm_unique_callbacks =
2729
std::unique_ptr<mongoc_apm_callbacks_t, decltype(libmongoc::apm_callbacks_destroy)>;
2830

31+
// An APM callback exiting via an exception is documented as being undefined behavior.
32+
// For QoI, terminate the program before allowing the exception to bypass libmongoc code.
33+
template <typename Fn>
34+
static void exception_guard(const char* source, Fn fn) noexcept {
35+
try {
36+
fn();
37+
} catch (...) {
38+
std::cerr << "fatal error: APM callback " << source << " exited via an exception"
39+
<< std::endl;
40+
std::terminate();
41+
}
42+
}
43+
2944
static void command_started(const mongoc_apm_command_started_t* event) noexcept {
3045
mongocxx::events::command_started_event started_event(static_cast<const void*>(event));
3146
auto context = static_cast<apm*>(libmongoc::apm_command_started_get_context(event));
32-
context->command_started()(started_event);
47+
exception_guard(__func__, [&] { context->command_started()(started_event); });
3348
}
3449

3550
static void command_failed(const mongoc_apm_command_failed_t* event) noexcept {
3651
mongocxx::events::command_failed_event failed_event(static_cast<const void*>(event));
3752
auto context = static_cast<apm*>(libmongoc::apm_command_failed_get_context(event));
38-
context->command_failed()(failed_event);
53+
exception_guard(__func__, [&] { context->command_failed()(failed_event); });
3954
}
4055

4156
static void command_succeeded(const mongoc_apm_command_succeeded_t* event) noexcept {
4257
mongocxx::events::command_succeeded_event succeeded_event(static_cast<const void*>(event));
4358
auto context = static_cast<apm*>(libmongoc::apm_command_succeeded_get_context(event));
44-
context->command_succeeded()(succeeded_event);
59+
exception_guard(__func__, [&] { context->command_succeeded()(succeeded_event); });
4560
}
4661

4762
static void server_closed(const mongoc_apm_server_closed_t* event) noexcept {
4863
mongocxx::events::server_closed_event e(static_cast<const void*>(event));
4964
auto context = static_cast<apm*>(libmongoc::apm_server_closed_get_context(event));
50-
context->server_closed()(e);
65+
exception_guard(__func__, [&] { context->server_closed()(e); });
5166
}
5267

5368
static void server_changed(const mongoc_apm_server_changed_t* event) noexcept {
5469
mongocxx::events::server_changed_event e(static_cast<const void*>(event));
5570
auto context = static_cast<apm*>(libmongoc::apm_server_changed_get_context(event));
56-
context->server_changed()(e);
71+
exception_guard(__func__, [&] { context->server_changed()(e); });
5772
}
5873

5974
static void server_opening(const mongoc_apm_server_opening_t* event) noexcept {
6075
mongocxx::events::server_opening_event e(static_cast<const void*>(event));
6176
auto context = static_cast<apm*>(libmongoc::apm_server_opening_get_context(event));
62-
context->server_opening()(e);
77+
exception_guard(__func__, [&] { context->server_opening()(e); });
6378
}
6479

6580
static void topology_closed(const mongoc_apm_topology_closed_t* event) noexcept {
6681
mongocxx::events::topology_closed_event e(static_cast<const void*>(event));
6782
auto context = static_cast<apm*>(libmongoc::apm_topology_closed_get_context(event));
68-
context->topology_closed()(e);
83+
exception_guard(__func__, [&] { context->topology_closed()(e); });
6984
}
7085

7186
static void topology_changed(const mongoc_apm_topology_changed_t* event) noexcept {
7287
mongocxx::events::topology_changed_event e(static_cast<const void*>(event));
7388
auto context = static_cast<apm*>(libmongoc::apm_topology_changed_get_context(event));
74-
context->topology_changed()(e);
89+
exception_guard(__func__, [&] { context->topology_changed()(e); });
7590
}
7691

7792
static void topology_opening(const mongoc_apm_topology_opening_t* event) noexcept {
7893
mongocxx::events::topology_opening_event e(static_cast<const void*>(event));
7994
auto context = static_cast<apm*>(libmongoc::apm_topology_opening_get_context(event));
80-
context->topology_opening()(e);
95+
exception_guard(__func__, [&] { context->topology_opening()(e); });
8196
}
8297

8398
static void heartbeat_started(const mongoc_apm_server_heartbeat_started_t* event) noexcept {
8499
mongocxx::events::heartbeat_started_event started_event(static_cast<const void*>(event));
85100
auto context = static_cast<apm*>(libmongoc::apm_server_heartbeat_started_get_context(event));
86-
context->heartbeat_started()(started_event);
101+
exception_guard(__func__, [&] { context->heartbeat_started()(started_event); });
87102
}
88103

89104
static void heartbeat_failed(const mongoc_apm_server_heartbeat_failed_t* event) noexcept {
90105
mongocxx::events::heartbeat_failed_event failed_event(static_cast<const void*>(event));
91106
auto context = static_cast<apm*>(libmongoc::apm_server_heartbeat_failed_get_context(event));
92-
context->heartbeat_failed()(failed_event);
107+
exception_guard(__func__, [&] { context->heartbeat_failed()(failed_event); });
93108
}
94109

95110
static void heartbeat_succeeded(const mongoc_apm_server_heartbeat_succeeded_t* event) noexcept {
96111
mongocxx::events::heartbeat_succeeded_event succeeded_event(static_cast<const void*>(event));
97112
auto context = static_cast<apm*>(libmongoc::apm_server_heartbeat_succeeded_get_context(event));
98-
context->heartbeat_succeeded()(succeeded_event);
113+
exception_guard(__func__, [&] { context->heartbeat_succeeded()(succeeded_event); });
99114
}
100115

101116
static apm_unique_callbacks make_apm_callbacks(const apm& apm_opts) {

0 commit comments

Comments
 (0)