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 35extern "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 49namespace { 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. 55static 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. 60static 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. 68static void 69err_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. 85static void 86crash_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. 110static void 111install_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. 136static std::string 137format_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. 162void 163utils::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. 183void 184utils::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