1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/experimental/symbolizer/test/SignalHandlerTest.h>
18
19 #include <folly/experimental/symbolizer/SignalHandler.h>
20
21 #include <folly/CPortability.h>
22 #include <folly/FileUtil.h>
23 #include <folly/Range.h>
24 #include <folly/experimental/coro/BlockingWait.h>
25 #include <folly/experimental/coro/Task.h>
26 #include <folly/portability/GTest.h>
27
28 #include <glog/logging.h>
29
30 namespace folly {
31 namespace symbolizer {
32 namespace test {
33
34 namespace {
35
print(StringPiece sp)36 void print(StringPiece sp) {
37 writeFull(STDERR_FILENO, sp.data(), sp.size());
38 }
39
callback1()40 void callback1() {
41 print("Callback1\n");
42 }
43
callback2()44 void callback2() {
45 if (fatalSignalReceived()) {
46 print("Callback2\n");
47 }
48 }
49
funcC()50 [[noreturn]] FOLLY_NOINLINE void funcC() {
51 LOG(FATAL) << "Die";
52 }
53
co_funcB()54 FOLLY_NOINLINE folly::coro::Task<void> co_funcB() {
55 funcC();
56 co_return;
57 }
58
co_funcA()59 FOLLY_NOINLINE folly::coro::Task<void> co_funcA() {
60 co_await co_funcB();
61 }
62
63 } // namespace
64
TEST(SignalHandler,Simple)65 TEST(SignalHandler, Simple) {
66 addFatalSignalCallback(callback1);
67 addFatalSignalCallback(callback2);
68 installFatalSignalHandler();
69 installFatalSignalCallbacks();
70
71 EXPECT_FALSE(fatalSignalReceived());
72
73 EXPECT_DEATH(
74 failHard(),
75 "^\\*\\*\\* Aborted at [0-9]+ \\(Unix time, try 'date -d @[0-9]+'\\) "
76 "\\*\\*\\*\n"
77 "\\*\\*\\* Signal 11 \\(SIGSEGV\\) \\(0x2a\\) received by PID [0-9]+ "
78 "\\(pthread TID 0x[0-9a-f]+\\) \\(linux TID [0-9]+\\) "
79 "\\(code: address not mapped to object\\), "
80 "stack trace: \\*\\*\\*\n"
81 ".*\n"
82 ".* @ [0-9a-f]+.* folly::symbolizer::test::SignalHandler_Simple_Test"
83 "::TestBody\\(\\).*\n"
84 ".*\n"
85 ".* @ [0-9a-f]+.* main.*\n"
86 ".*\n"
87 "Callback1\n"
88 "Callback2\n"
89 ".*");
90 }
91
TEST(SignalHandler,AsyncStackTraceSimple)92 TEST(SignalHandler, AsyncStackTraceSimple) {
93 addFatalSignalCallback(callback1);
94 addFatalSignalCallback(callback2);
95 installFatalSignalHandler();
96 installFatalSignalCallbacks();
97
98 EXPECT_DEATH(
99 folly::coro::blockingWait(co_funcA()),
100 "\\*\\*\\* Aborted at [0-9]+ \\(Unix time, try 'date -d @[0-9]+'\\) "
101 "\\*\\*\\*\n"
102 "\\*\\*\\* Signal 6 \\(SIGABRT\\) \\(0x[0-9a-f]+\\) received by PID [0-9]+ "
103 "\\(pthread TID 0x[0-9a-f]+\\) \\(linux TID [0-9]+\\) .*, "
104 "stack trace: \\*\\*\\*\n"
105 ".*\n"
106 ".* @ [0-9a-f]+.* folly::symbolizer::test::SignalHandler"
107 "_AsyncStackTraceSimple_Test::TestBody\\(\\).*\n"
108 ".*\n"
109 ".* @ [0-9a-f]+.* main.*\n"
110 ".*\n"
111 "\\*\\*\\* Check failure async stack trace: \\*\\*\\*\n"
112 "\\*\\*\\* First async stack root.* \\*\\*\\*\n"
113 "\\*\\*\\* First async stack frame pointer.* \\*\\*\\*\n"
114 ".*\n"
115 ".* @ [0-9a-f]+.* folly::symbolizer::test::\\(anonymous namespace\\)"
116 "::funcC.*\n"
117 ".*\n"
118 ".* @ [0-9a-f]+.* folly::symbolizer::test::\\(anonymous namespace\\)"
119 "::co_funcB.*\n"
120 ".*\n"
121 ".* @ [0-9a-f]+.* folly::symbolizer::test::\\(anonymous namespace\\)"
122 "::co_funcA.*\n"
123 ".*\n"
124 "Callback1\n"
125 "Callback2\n"
126 ".*");
127 }
128 } // namespace test
129 } // namespace symbolizer
130 } // namespace folly
131
132 // Can't use initFacebookLight since that would install its own signal handlers
133 // Can't use initFacebookNoSignals since we cannot depend on common
main(int argc,char ** argv)134 int main(int argc, char** argv) {
135 ::testing::InitGoogleTest(&argc, argv);
136 return RUN_ALL_TESTS();
137 }
138