Improve the process for GNU tools
[minix3.git] / external / bsd / kyua-cli / dist / utils / sanity.cpp
blobcfba6e99bcb7021e476d24a6f32dadfaefed47e3
1 // Copyright 2010 Google Inc.
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.
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.
29 #include "utils/sanity.hpp"
31 #if defined(HAVE_CONFIG_H)
32 #include "config.h"
33 #endif
35 extern "C" {
36 #include <signal.h>
37 #include <unistd.h>
40 #include <cerrno>
41 #include <cstdlib>
42 #include <cstring>
43 #include <iostream>
45 #include "utils/format/macros.hpp"
46 #include "utils/logging/macros.hpp"
49 namespace {
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 };
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;
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)
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.
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)
88 PRE(!logfile.empty());
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);
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);
103 /// Installs a handler for a fatal signal representing a crash.
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.
109 /// \param signo The fatal signal for which to install a handler.
110 static void
111 install_one_crash_handler(const int signo)
113 struct ::sigaction sa;
114 sa.sa_handler = crash_handler;
115 sigemptyset(&sa.sa_mask);
116 sa.sa_flags = SA_RESETHAND;
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);
127 /// Returns a textual representation of an assertion type.
129 /// The textual representation is user facing.
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.
135 /// \return A textual description of the assertion type.
136 static std::string
137 format_type(const utils::assert_type type)
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";
149 } // anonymous namespace
152 /// Raises an assertion error.
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.
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)
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();
175 /// Installs persistent handlers for crash signals.
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.
180 /// \pre The function has not been called before.
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_)
186 #if !defined(NDEBUG) && defined(__minix)
187 static bool installed = false;
188 #endif /* !defined(NDEBUG) && defined(__minix) */
189 PRE(!installed);
190 logfile = logfile_;
192 for (const int* iter = &fatal_signals[0]; *iter != 0; iter++)
193 install_one_crash_handler(*iter);
195 #if !defined(NDEBUG) && defined(__minix)
196 installed = true;
197 #endif /* !defined(NDEBUG) && defined(__minix) */