1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/sanity.hpp"
30
31 #if defined(HAVE_CONFIG_H)
32 #include "config.h"
33 #endif
34
35 extern "C" {
36 #include <signal.h>
37 #include <unistd.h>
38 }
39
40 #include <cerrno>
41 #include <cstdlib>
42 #include <cstring>
43 #include <iostream>
44
45 #include "utils/format/macros.hpp"
46 #include "utils/logging/macros.hpp"
47
48
49 namespace {
50
51
52 /// List of fatal signals to be intercepted by the sanity code.
53 ///
54 /// The tests hardcode this list; update them whenever the list gets updated.
55 static int fatal_signals[] = { SIGABRT, SIGBUS, SIGSEGV, 0 };
56
57
58 /// The path to the log file to report on crashes. Be aware that this is empty
59 /// until install_crash_handlers() is called.
60 static std::string logfile;
61
62
63 /// Prints a message to stderr.
64 ///
65 /// Note that this runs from a signal handler. Calling write() is OK.
66 ///
67 /// \param message The message to print.
68 static void
err_write(const std::string & message)69 err_write(const std::string& message)
70 {
71 if (::write(STDERR_FILENO, message.c_str(), message.length()) == -1) {
72 // We are crashing. If ::write fails, there is not much we could do,
73 // specially considering that we are running within a signal handler.
74 // Just ignore the error.
75 }
76 }
77
78
79 /// The crash handler for fatal signals.
80 ///
81 /// The sole purpose of this is to print some informational data before
82 /// reraising the original signal.
83 ///
84 /// \param signo The received signal.
85 static void
crash_handler(const int signo)86 crash_handler(const int signo)
87 {
88 PRE(!logfile.empty());
89
90 err_write(F("*** Fatal signal %s received\n") % signo);
91 err_write(F("*** Log file is %s\n") % logfile);
92 err_write(F("*** Please report this problem to %s detailing what you were "
93 "doing before the crash happened; if possible, include the log "
94 "file mentioned above\n") % PACKAGE_BUGREPORT);
95
96 /// The handler is installed with SA_RESETHAND, so this is safe to do. We
97 /// really want to call the default handler to generate any possible core
98 /// dumps.
99 ::kill(::getpid(), signo);
100 }
101
102
103 /// Installs a handler for a fatal signal representing a crash.
104 ///
105 /// When the specified signal is captured, the crash_handler() will be called to
106 /// print some informational details to the user and, later, the signal will be
107 /// redelivered using the default handler to obtain a core dump.
108 ///
109 /// \param signo The fatal signal for which to install a handler.
110 static void
install_one_crash_handler(const int signo)111 install_one_crash_handler(const int signo)
112 {
113 struct ::sigaction sa;
114 sa.sa_handler = crash_handler;
115 sigemptyset(&sa.sa_mask);
116 sa.sa_flags = SA_RESETHAND;
117
118 if (::sigaction(signo, &sa, NULL) == -1) {
119 const int original_errno = errno;
120 LW(F("Could not install crash handler for signal %s: %s") %
121 signo % std::strerror(original_errno));
122 } else
123 LD(F("Installed crash handler for signal %s") % signo);
124 }
125
126
127 /// Returns a textual representation of an assertion type.
128 ///
129 /// The textual representation is user facing.
130 ///
131 /// \param type The type of the assertion. If the type is unknown for whatever
132 /// reason, a special message is returned. The code cannot abort in such a
133 /// case because this code is dealing for assertion errors.
134 ///
135 /// \return A textual description of the assertion type.
136 static std::string
format_type(const utils::assert_type type)137 format_type(const utils::assert_type type)
138 {
139 switch (type) {
140 case utils::invariant: return "Invariant check failed";
141 case utils::postcondition: return "Postcondition check failed";
142 case utils::precondition: return "Precondition check failed";
143 case utils::unreachable: return "Unreachable point reached";
144 default: return "UNKNOWN ASSERTION TYPE";
145 }
146 }
147
148
149 } // anonymous namespace
150
151
152 /// Raises an assertion error.
153 ///
154 /// This function prints information about the assertion failure and terminates
155 /// execution immediately by calling std::abort(). This ensures a coredump so
156 /// that the failure can be analyzed later.
157 ///
158 /// \param type The assertion type; this influences the printed message.
159 /// \param file The file in which the assertion failed.
160 /// \param line The line in which the assertion failed.
161 /// \param message The failure message associated to the condition.
162 void
sanity_failure(const assert_type type,const char * file,const size_t line,const std::string & message)163 utils::sanity_failure(const assert_type type, const char* file,
164 const size_t line, const std::string& message)
165 {
166 std::cerr << "*** " << file << ":" << line << ": " << format_type(type);
167 if (!message.empty())
168 std::cerr << ": " << message << "\n";
169 else
170 std::cerr << "\n";
171 std::abort();
172 }
173
174
175 /// Installs persistent handlers for crash signals.
176 ///
177 /// Should be called at the very beginning of the execution of the program to
178 /// ensure that a signal handler for fatal crash signals is installed.
179 ///
180 /// \pre The function has not been called before.
181 ///
182 /// \param logfile_ The path to the log file to report during a crash.
183 void
install_crash_handlers(const std::string & logfile_)184 utils::install_crash_handlers(const std::string& logfile_)
185 {
186 static bool installed = false;
187 PRE(!installed);
188 logfile = logfile_;
189
190 for (const int* iter = &fatal_signals[0]; *iter != 0; iter++)
191 install_one_crash_handler(*iter);
192
193 installed = true;
194 }
195