aboutsummaryrefslogtreecommitdiff
path: root/utils/sanity.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sanity.cpp')
-rw-r--r--utils/sanity.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/utils/sanity.cpp b/utils/sanity.cpp
new file mode 100644
index 000000000000..7978167d83ff
--- /dev/null
+++ b/utils/sanity.cpp
@@ -0,0 +1,194 @@
+// Copyright 2010 The Kyua Authors.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "utils/sanity.hpp"
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+extern "C" {
+#include <signal.h>
+#include <unistd.h>
+}
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+#include "utils/format/macros.hpp"
+#include "utils/logging/macros.hpp"
+
+
+namespace {
+
+
+/// List of fatal signals to be intercepted by the sanity code.
+///
+/// The tests hardcode this list; update them whenever the list gets updated.
+static int fatal_signals[] = { SIGABRT, SIGBUS, SIGSEGV, 0 };
+
+
+/// The path to the log file to report on crashes. Be aware that this is empty
+/// until install_crash_handlers() is called.
+static std::string logfile;
+
+
+/// Prints a message to stderr.
+///
+/// Note that this runs from a signal handler. Calling write() is OK.
+///
+/// \param message The message to print.
+static void
+err_write(const std::string& message)
+{
+ if (::write(STDERR_FILENO, message.c_str(), message.length()) == -1) {
+ // We are crashing. If ::write fails, there is not much we could do,
+ // specially considering that we are running within a signal handler.
+ // Just ignore the error.
+ }
+}
+
+
+/// The crash handler for fatal signals.
+///
+/// The sole purpose of this is to print some informational data before
+/// reraising the original signal.
+///
+/// \param signo The received signal.
+static void
+crash_handler(const int signo)
+{
+ PRE(!logfile.empty());
+
+ err_write(F("*** Fatal signal %s received\n") % signo);
+ err_write(F("*** Log file is %s\n") % logfile);
+ err_write(F("*** Please report this problem to %s detailing what you were "
+ "doing before the crash happened; if possible, include the log "
+ "file mentioned above\n") % PACKAGE_BUGREPORT);
+
+ /// The handler is installed with SA_RESETHAND, so this is safe to do. We
+ /// really want to call the default handler to generate any possible core
+ /// dumps.
+ ::kill(::getpid(), signo);
+}
+
+
+/// Installs a handler for a fatal signal representing a crash.
+///
+/// When the specified signal is captured, the crash_handler() will be called to
+/// print some informational details to the user and, later, the signal will be
+/// redelivered using the default handler to obtain a core dump.
+///
+/// \param signo The fatal signal for which to install a handler.
+static void
+install_one_crash_handler(const int signo)
+{
+ struct ::sigaction sa;
+ sa.sa_handler = crash_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESETHAND;
+
+ if (::sigaction(signo, &sa, NULL) == -1) {
+ const int original_errno = errno;
+ LW(F("Could not install crash handler for signal %s: %s") %
+ signo % std::strerror(original_errno));
+ } else
+ LD(F("Installed crash handler for signal %s") % signo);
+}
+
+
+/// Returns a textual representation of an assertion type.
+///
+/// The textual representation is user facing.
+///
+/// \param type The type of the assertion. If the type is unknown for whatever
+/// reason, a special message is returned. The code cannot abort in such a
+/// case because this code is dealing for assertion errors.
+///
+/// \return A textual description of the assertion type.
+static std::string
+format_type(const utils::assert_type type)
+{
+ switch (type) {
+ case utils::invariant: return "Invariant check failed";
+ case utils::postcondition: return "Postcondition check failed";
+ case utils::precondition: return "Precondition check failed";
+ case utils::unreachable: return "Unreachable point reached";
+ default: return "UNKNOWN ASSERTION TYPE";
+ }
+}
+
+
+} // anonymous namespace
+
+
+/// Raises an assertion error.
+///
+/// This function prints information about the assertion failure and terminates
+/// execution immediately by calling std::abort(). This ensures a coredump so
+/// that the failure can be analyzed later.
+///
+/// \param type The assertion type; this influences the printed message.
+/// \param file The file in which the assertion failed.
+/// \param line The line in which the assertion failed.
+/// \param message The failure message associated to the condition.
+void
+utils::sanity_failure(const assert_type type, const char* file,
+ const size_t line, const std::string& message)
+{
+ std::cerr << "*** " << file << ":" << line << ": " << format_type(type);
+ if (!message.empty())
+ std::cerr << ": " << message << "\n";
+ else
+ std::cerr << "\n";
+ std::abort();
+}
+
+
+/// Installs persistent handlers for crash signals.
+///
+/// Should be called at the very beginning of the execution of the program to
+/// ensure that a signal handler for fatal crash signals is installed.
+///
+/// \pre The function has not been called before.
+///
+/// \param logfile_ The path to the log file to report during a crash.
+void
+utils::install_crash_handlers(const std::string& logfile_)
+{
+ static bool installed = false;
+ PRE(!installed);
+ logfile = logfile_;
+
+ for (const int* iter = &fatal_signals[0]; *iter != 0; iter++)
+ install_one_crash_handler(*iter);
+
+ installed = true;
+}