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