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 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 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 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 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 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 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