2
2
3
3
#include < csignal>
4
4
5
+ #include " common/signal/fatal_error_handler.h"
5
6
#include " common/signal/signal_action.h"
6
7
8
+ #include " test/common/stats/stat_test_utility.h"
7
9
#include " test/test_common/utility.h"
8
10
9
11
#include " gtest/gtest.h"
@@ -19,6 +21,12 @@ namespace Envoy {
19
21
#define ASANITIZED /* Sanitized by GCC */
20
22
#endif
21
23
24
+ // Use this test handler instead of a mock, because fatal error handlers must be
25
+ // signal-safe and a mock might allocate memory.
26
+ class TestFatalErrorHandler : public FatalErrorHandlerInterface {
27
+ void onFatalError (std::ostream& os) const override { os << " HERE!" ; }
28
+ };
29
+
22
30
// Death tests that expect a particular output are disabled under address sanitizer.
23
31
// The sanitizer does its own special signal handling and prints messages that are
24
32
// not ours instead of what this test expects. As of latest Clang this appears
@@ -35,13 +43,9 @@ TEST(SignalsDeathTest, InvalidAddressDeathTest) {
35
43
" backtrace.*Segmentation fault" );
36
44
}
37
45
38
- class TestFatalErrorHandler : public FatalErrorHandlerInterface {
39
- void onFatalError () const override { std::cerr << " HERE!" ; }
40
- };
41
-
42
46
TEST (SignalsDeathTest, RegisteredHandlerTest) {
43
47
TestFatalErrorHandler handler;
44
- SignalAction ::registerFatalErrorHandler (handler);
48
+ FatalErrorHandler ::registerFatalErrorHandler (handler);
45
49
SignalAction actions;
46
50
// Make sure the fatal error log "HERE" registered above is logged on fatal error.
47
51
EXPECT_DEATH (
@@ -51,7 +55,7 @@ TEST(SignalsDeathTest, RegisteredHandlerTest) {
51
55
*(nasty_ptr) = 0 ; // NOLINT(clang-analyzer-core.NullDereference)
52
56
}(),
53
57
" HERE" );
54
- SignalAction ::removeFatalErrorHandler (handler);
58
+ FatalErrorHandler ::removeFatalErrorHandler (handler);
55
59
}
56
60
57
61
TEST (SignalsDeathTest, BusDeathTest) {
@@ -145,4 +149,60 @@ TEST(Signals, HandlerTest) {
145
149
SignalAction::sigHandler (SIGURG, &fake_si, nullptr );
146
150
}
147
151
152
+ TEST (FatalErrorHandler, CallHandler) {
153
+ // Reserve space in advance so that the handler doesn't allocate memory.
154
+ std::string s;
155
+ s.reserve (1024 );
156
+ std::ostringstream os (std::move (s));
157
+
158
+ TestFatalErrorHandler handler;
159
+ FatalErrorHandler::registerFatalErrorHandler (handler);
160
+
161
+ FatalErrorHandler::callFatalErrorHandlers (os);
162
+ EXPECT_EQ (os.str (), " HERE!" );
163
+
164
+ // callFatalErrorHandlers() will unregister the handler, so this isn't
165
+ // necessary for cleanup. Call it anyway, to simulate the case when one thread
166
+ // tries to remove the handler while another thread crashes.
167
+ FatalErrorHandler::removeFatalErrorHandler (handler);
168
+ }
169
+
170
+ // Use this specialized test handler instead of a mock, because fatal error
171
+ // handlers must be signal-safe and a mock might allocate memory.
172
+ class MemoryCheckingFatalErrorHandler : public FatalErrorHandlerInterface {
173
+ public:
174
+ MemoryCheckingFatalErrorHandler (const Stats::TestUtil::MemoryTest& memory_test,
175
+ uint64_t & allocated_after_call)
176
+ : memory_test_(memory_test), allocated_after_call_(allocated_after_call) {}
177
+ void onFatalError (std::ostream& os) const override {
178
+ UNREFERENCED_PARAMETER (os);
179
+ allocated_after_call_ = memory_test_.consumedBytes ();
180
+ }
181
+
182
+ private:
183
+ const Stats::TestUtil::MemoryTest& memory_test_;
184
+ uint64_t & allocated_after_call_;
185
+ };
186
+
187
+ // FatalErrorHandler::callFatalErrorHandlers shouldn't allocate any heap memory,
188
+ // so that it's safe to call from a signal handler. Test by comparing the
189
+ // allocated memory before a call with the allocated memory during a handler.
190
+ TEST (FatalErrorHandler, DontAllocateMemory) {
191
+ // Reserve space in advance so that the handler doesn't allocate memory.
192
+ std::string s;
193
+ s.reserve (1024 );
194
+ std::ostringstream os (std::move (s));
195
+
196
+ Stats::TestUtil::MemoryTest memory_test;
197
+
198
+ uint64_t allocated_after_call;
199
+ MemoryCheckingFatalErrorHandler handler (memory_test, allocated_after_call);
200
+ FatalErrorHandler::registerFatalErrorHandler (handler);
201
+
202
+ uint64_t allocated_before_call = memory_test.consumedBytes ();
203
+ FatalErrorHandler::callFatalErrorHandlers (os);
204
+
205
+ EXPECT_MEMORY_EQ (allocated_after_call, allocated_before_call);
206
+ }
207
+
148
208
} // namespace Envoy
0 commit comments