blob: bb2cc48eb4a602601ee8047f9aefffec79b4a554 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -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//
8// https://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 "absl/debugging/failure_signal_handler.h"
18
19#include <csignal>
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <fstream>
24
25#include "gtest/gtest.h"
26#include "absl/base/internal/raw_logging.h"
27#include "absl/debugging/stacktrace.h"
28#include "absl/debugging/symbolize.h"
29#include "absl/strings/match.h"
30#include "absl/strings/str_cat.h"
31
32namespace {
33
34#if GTEST_HAS_DEATH_TEST
35
36// For the parameterized death tests. GetParam() returns the signal number.
37using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
38
39// This function runs in a fork()ed process on most systems.
40void InstallHandlerAndRaise(int signo) {
41 absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
42 raise(signo);
43}
44
45TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
46 const int signo = GetParam();
47 std::string exit_regex = absl::StrCat(
48 "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
49 " received at time=");
50#ifndef _WIN32
51 EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
52 exit_regex);
53#else
54 // Windows doesn't have testing::KilledBySignal().
55 EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
56#endif
57}
58
59ABSL_CONST_INIT FILE* error_file = nullptr;
60
61void WriteToErrorFile(const char* msg) {
62 if (msg != nullptr) {
63 ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
64 "fwrite() failed");
65 }
66 ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
67}
68
69std::string GetTmpDir() {
70 // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
71 static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
72 "TEMPDIR", "TMP"};
73 for (const char* const var : kTmpEnvVars) {
74 const char* tmp_dir = std::getenv(var);
75 if (tmp_dir != nullptr) {
76 return tmp_dir;
77 }
78 }
79
80 // Try something reasonable.
81 return "/tmp";
82}
83
84// This function runs in a fork()ed process on most systems.
85void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
86 error_file = fopen(file, "w");
87 ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file");
88 absl::FailureSignalHandlerOptions options;
89 options.writerfn = WriteToErrorFile;
90 absl::InstallFailureSignalHandler(options);
91 raise(signo);
92}
93
94TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
95 const int signo = GetParam();
96 std::string tmp_dir = GetTmpDir();
97 std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
98
99 std::string exit_regex = absl::StrCat(
100 "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
101 " received at time=");
102#ifndef _WIN32
103 EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
104 testing::KilledBySignal(signo), exit_regex);
105#else
106 // Windows doesn't have testing::KilledBySignal().
107 EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
108 exit_regex);
109#endif
110
111 // Open the file in this process and check its contents.
112 std::fstream error_output(file);
113 ASSERT_TRUE(error_output.is_open()) << file;
114 std::string error_line;
115 std::getline(error_output, error_line);
116 EXPECT_TRUE(absl::StartsWith(
117 error_line,
118 absl::StrCat("*** ",
119 absl::debugging_internal::FailureSignalToString(signo),
120 " received at ")));
121
122 if (absl::debugging_internal::StackTraceWorksForTest()) {
123 std::getline(error_output, error_line);
124 EXPECT_TRUE(absl::StartsWith(error_line, "PC: "));
125 }
126}
127
128constexpr int kFailureSignals[] = {
129 SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM,
130#ifndef _WIN32
131 SIGBUS, SIGTRAP,
132#endif
133};
134
135std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
136 std::string result =
137 absl::debugging_internal::FailureSignalToString(info.param);
138 if (result.empty()) {
139 result = absl::StrCat(info.param);
140 }
141 return result;
142}
143
144INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
145 ::testing::ValuesIn(kFailureSignals),
146 SignalParamToString);
147
148#endif // GTEST_HAS_DEATH_TEST
149
150} // namespace
151
152int main(int argc, char** argv) {
153 absl::InitializeSymbolizer(argv[0]);
154 testing::InitGoogleTest(&argc, argv);
155 return RUN_ALL_TESTS();
156}