14
14
15
15
#pragma once
16
16
17
+ #include < iostream>
18
+
17
19
#include < mongocxx/options/apm.hpp>
18
20
#include < mongocxx/private/libmongoc.hh>
19
21
@@ -26,76 +28,89 @@ namespace options {
26
28
using apm_unique_callbacks =
27
29
std::unique_ptr<mongoc_apm_callbacks_t , decltype (libmongoc::apm_callbacks_destroy)>;
28
30
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
+
29
44
static void command_started (const mongoc_apm_command_started_t * event) noexcept {
30
45
mongocxx::events::command_started_event started_event (static_cast <const void *>(event));
31
46
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); } );
33
48
}
34
49
35
50
static void command_failed (const mongoc_apm_command_failed_t * event) noexcept {
36
51
mongocxx::events::command_failed_event failed_event (static_cast <const void *>(event));
37
52
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); } );
39
54
}
40
55
41
56
static void command_succeeded (const mongoc_apm_command_succeeded_t * event) noexcept {
42
57
mongocxx::events::command_succeeded_event succeeded_event (static_cast <const void *>(event));
43
58
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); } );
45
60
}
46
61
47
62
static void server_closed (const mongoc_apm_server_closed_t * event) noexcept {
48
63
mongocxx::events::server_closed_event e (static_cast <const void *>(event));
49
64
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); } );
51
66
}
52
67
53
68
static void server_changed (const mongoc_apm_server_changed_t * event) noexcept {
54
69
mongocxx::events::server_changed_event e (static_cast <const void *>(event));
55
70
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); } );
57
72
}
58
73
59
74
static void server_opening (const mongoc_apm_server_opening_t * event) noexcept {
60
75
mongocxx::events::server_opening_event e (static_cast <const void *>(event));
61
76
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); } );
63
78
}
64
79
65
80
static void topology_closed (const mongoc_apm_topology_closed_t * event) noexcept {
66
81
mongocxx::events::topology_closed_event e (static_cast <const void *>(event));
67
82
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); } );
69
84
}
70
85
71
86
static void topology_changed (const mongoc_apm_topology_changed_t * event) noexcept {
72
87
mongocxx::events::topology_changed_event e (static_cast <const void *>(event));
73
88
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); } );
75
90
}
76
91
77
92
static void topology_opening (const mongoc_apm_topology_opening_t * event) noexcept {
78
93
mongocxx::events::topology_opening_event e (static_cast <const void *>(event));
79
94
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); } );
81
96
}
82
97
83
98
static void heartbeat_started (const mongoc_apm_server_heartbeat_started_t * event) noexcept {
84
99
mongocxx::events::heartbeat_started_event started_event (static_cast <const void *>(event));
85
100
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); } );
87
102
}
88
103
89
104
static void heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t * event) noexcept {
90
105
mongocxx::events::heartbeat_failed_event failed_event (static_cast <const void *>(event));
91
106
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); } );
93
108
}
94
109
95
110
static void heartbeat_succeeded (const mongoc_apm_server_heartbeat_succeeded_t * event) noexcept {
96
111
mongocxx::events::heartbeat_succeeded_event succeeded_event (static_cast <const void *>(event));
97
112
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); } );
99
114
}
100
115
101
116
static apm_unique_callbacks make_apm_callbacks (const apm& apm_opts) {
0 commit comments