blob: 72816a3e727cb7f5d093e7aa1c26e0f8154f3b94 [file] [log] [blame]
Abseil Team28f5b892018-04-26 06:47:58 -07001//
2// Copyright 2018 The Abseil Authors.
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//
nik727338b70432019-03-08 10:27:53 -05008// https://www.apache.org/licenses/LICENSE-2.0
Abseil Team28f5b892018-04-26 06:47:58 -07009//
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 "absl/debugging/failure_signal_handler.h"
18
19#include <csignal>
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <fstream>
24
Abseil Team20de2db2019-11-04 07:46:04 -080025#include "gmock/gmock.h"
Andy Getzendanner52747822023-05-23 15:46:35 -070026#include "gtest/gtest.h"
Abseil Team28f5b892018-04-26 06:47:58 -070027#include "absl/base/internal/raw_logging.h"
28#include "absl/debugging/stacktrace.h"
29#include "absl/debugging/symbolize.h"
Andy Getzendanner52747822023-05-23 15:46:35 -070030#include "absl/log/check.h"
Abseil Team28f5b892018-04-26 06:47:58 -070031#include "absl/strings/match.h"
32#include "absl/strings/str_cat.h"
33
34namespace {
35
Abseil Team20de2db2019-11-04 07:46:04 -080036using testing::StartsWith;
37
Abseil Team28f5b892018-04-26 06:47:58 -070038#if GTEST_HAS_DEATH_TEST
39
40// For the parameterized death tests. GetParam() returns the signal number.
41using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
42
43// This function runs in a fork()ed process on most systems.
44void InstallHandlerAndRaise(int signo) {
45 absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
46 raise(signo);
47}
48
49TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
50 const int signo = GetParam();
51 std::string exit_regex = absl::StrCat(
52 "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
53 " received at time=");
54#ifndef _WIN32
55 EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
56 exit_regex);
57#else
58 // Windows doesn't have testing::KilledBySignal().
Abseil Team902909a2020-04-22 10:52:29 -070059 EXPECT_DEATH_IF_SUPPORTED(InstallHandlerAndRaise(signo), exit_regex);
Abseil Team28f5b892018-04-26 06:47:58 -070060#endif
61}
62
63ABSL_CONST_INIT FILE* error_file = nullptr;
64
65void WriteToErrorFile(const char* msg) {
66 if (msg != nullptr) {
67 ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
68 "fwrite() failed");
69 }
70 ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
71}
72
73std::string GetTmpDir() {
74 // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
75 static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
76 "TEMPDIR", "TMP"};
77 for (const char* const var : kTmpEnvVars) {
78 const char* tmp_dir = std::getenv(var);
79 if (tmp_dir != nullptr) {
80 return tmp_dir;
81 }
82 }
83
84 // Try something reasonable.
85 return "/tmp";
86}
87
88// This function runs in a fork()ed process on most systems.
89void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
90 error_file = fopen(file, "w");
Andy Getzendanner52747822023-05-23 15:46:35 -070091 CHECK_NE(error_file, nullptr) << "Failed create error_file";
Abseil Team28f5b892018-04-26 06:47:58 -070092 absl::FailureSignalHandlerOptions options;
93 options.writerfn = WriteToErrorFile;
94 absl::InstallFailureSignalHandler(options);
95 raise(signo);
96}
97
98TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
99 const int signo = GetParam();
100 std::string tmp_dir = GetTmpDir();
101 std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
102
103 std::string exit_regex = absl::StrCat(
104 "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
105 " received at time=");
106#ifndef _WIN32
107 EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
108 testing::KilledBySignal(signo), exit_regex);
109#else
110 // Windows doesn't have testing::KilledBySignal().
Abseil Team902909a2020-04-22 10:52:29 -0700111 EXPECT_DEATH_IF_SUPPORTED(
112 InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), exit_regex);
Abseil Team28f5b892018-04-26 06:47:58 -0700113#endif
114
115 // Open the file in this process and check its contents.
116 std::fstream error_output(file);
117 ASSERT_TRUE(error_output.is_open()) << file;
118 std::string error_line;
119 std::getline(error_output, error_line);
Abseil Team20de2db2019-11-04 07:46:04 -0800120 EXPECT_THAT(
Abseil Team28f5b892018-04-26 06:47:58 -0700121 error_line,
Abseil Team20de2db2019-11-04 07:46:04 -0800122 StartsWith(absl::StrCat(
123 "*** ", absl::debugging_internal::FailureSignalToString(signo),
124 " received at ")));
Abseil Team28f5b892018-04-26 06:47:58 -0700125
Abseil Team322ae242021-01-12 07:36:20 -0800126 // On platforms where it is possible to get the current CPU, the
127 // CPU number is also logged. Check that it is present in output.
128#if defined(__linux__)
129 EXPECT_THAT(error_line, testing::HasSubstr(" on cpu "));
130#endif
131
Abseil Team28f5b892018-04-26 06:47:58 -0700132 if (absl::debugging_internal::StackTraceWorksForTest()) {
133 std::getline(error_output, error_line);
Abseil Team20de2db2019-11-04 07:46:04 -0800134 EXPECT_THAT(error_line, StartsWith("PC: "));
Abseil Team28f5b892018-04-26 06:47:58 -0700135 }
136}
137
138constexpr int kFailureSignals[] = {
139 SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM,
140#ifndef _WIN32
141 SIGBUS, SIGTRAP,
142#endif
143};
144
Abseil Team30de2042018-05-17 09:05:57 -0700145std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
Abseil Teamfebc5ee2019-03-06 11:36:55 -0800146 std::string result =
147 absl::debugging_internal::FailureSignalToString(info.param);
Abseil Team30de2042018-05-17 09:05:57 -0700148 if (result.empty()) {
149 result = absl::StrCat(info.param);
150 }
151 return result;
152}
153
Abseil Team5eea0f72019-01-11 10:16:39 -0800154INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
155 ::testing::ValuesIn(kFailureSignals),
156 SignalParamToString);
Abseil Team28f5b892018-04-26 06:47:58 -0700157
158#endif // GTEST_HAS_DEATH_TEST
159
160} // namespace
161
162int main(int argc, char** argv) {
163 absl::InitializeSymbolizer(argv[0]);
164 testing::InitGoogleTest(&argc, argv);
165 return RUN_ALL_TESTS();
166}