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