111be35a1SLionel Sambuc // Copyright 2010 Google Inc.
211be35a1SLionel Sambuc // All rights reserved.
311be35a1SLionel Sambuc //
411be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
511be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
611be35a1SLionel Sambuc // met:
711be35a1SLionel Sambuc //
811be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
911be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer.
1011be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
1111be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer in the
1211be35a1SLionel Sambuc // documentation and/or other materials provided with the distribution.
1311be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
1411be35a1SLionel Sambuc // may be used to endorse or promote products derived from this software
1511be35a1SLionel Sambuc // without specific prior written permission.
1611be35a1SLionel Sambuc //
1711be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1811be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1911be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2011be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2111be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2211be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2311be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2411be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2511be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2611be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2711be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc
2911be35a1SLionel Sambuc #include "utils/sanity.hpp"
3011be35a1SLionel Sambuc
3111be35a1SLionel Sambuc #if defined(HAVE_CONFIG_H)
3211be35a1SLionel Sambuc #include "config.h"
3311be35a1SLionel Sambuc #endif
3411be35a1SLionel Sambuc
3511be35a1SLionel Sambuc extern "C" {
3611be35a1SLionel Sambuc #include <signal.h>
3711be35a1SLionel Sambuc #include <unistd.h>
3811be35a1SLionel Sambuc }
3911be35a1SLionel Sambuc
4011be35a1SLionel Sambuc #include <cerrno>
4111be35a1SLionel Sambuc #include <cstdlib>
4211be35a1SLionel Sambuc #include <cstring>
4311be35a1SLionel Sambuc #include <iostream>
4411be35a1SLionel Sambuc
4511be35a1SLionel Sambuc #include "utils/format/macros.hpp"
4611be35a1SLionel Sambuc #include "utils/logging/macros.hpp"
4711be35a1SLionel Sambuc
4811be35a1SLionel Sambuc
4911be35a1SLionel Sambuc namespace {
5011be35a1SLionel Sambuc
5111be35a1SLionel Sambuc
5211be35a1SLionel Sambuc /// List of fatal signals to be intercepted by the sanity code.
5311be35a1SLionel Sambuc ///
5411be35a1SLionel Sambuc /// The tests hardcode this list; update them whenever the list gets updated.
5511be35a1SLionel Sambuc static int fatal_signals[] = { SIGABRT, SIGBUS, SIGSEGV, 0 };
5611be35a1SLionel Sambuc
5711be35a1SLionel Sambuc
5811be35a1SLionel Sambuc /// The path to the log file to report on crashes. Be aware that this is empty
5911be35a1SLionel Sambuc /// until install_crash_handlers() is called.
6011be35a1SLionel Sambuc static std::string logfile;
6111be35a1SLionel Sambuc
6211be35a1SLionel Sambuc
6311be35a1SLionel Sambuc /// Prints a message to stderr.
6411be35a1SLionel Sambuc ///
6511be35a1SLionel Sambuc /// Note that this runs from a signal handler. Calling write() is OK.
6611be35a1SLionel Sambuc ///
6711be35a1SLionel Sambuc /// \param message The message to print.
6811be35a1SLionel Sambuc static void
err_write(const std::string & message)6911be35a1SLionel Sambuc err_write(const std::string& message)
7011be35a1SLionel Sambuc {
7111be35a1SLionel Sambuc if (::write(STDERR_FILENO, message.c_str(), message.length()) == -1) {
7211be35a1SLionel Sambuc // We are crashing. If ::write fails, there is not much we could do,
7311be35a1SLionel Sambuc // specially considering that we are running within a signal handler.
7411be35a1SLionel Sambuc // Just ignore the error.
7511be35a1SLionel Sambuc }
7611be35a1SLionel Sambuc }
7711be35a1SLionel Sambuc
7811be35a1SLionel Sambuc
7911be35a1SLionel Sambuc /// The crash handler for fatal signals.
8011be35a1SLionel Sambuc ///
8111be35a1SLionel Sambuc /// The sole purpose of this is to print some informational data before
8211be35a1SLionel Sambuc /// reraising the original signal.
8311be35a1SLionel Sambuc ///
8411be35a1SLionel Sambuc /// \param signo The received signal.
8511be35a1SLionel Sambuc static void
crash_handler(const int signo)8611be35a1SLionel Sambuc crash_handler(const int signo)
8711be35a1SLionel Sambuc {
8811be35a1SLionel Sambuc PRE(!logfile.empty());
8911be35a1SLionel Sambuc
9011be35a1SLionel Sambuc err_write(F("*** Fatal signal %s received\n") % signo);
9111be35a1SLionel Sambuc err_write(F("*** Log file is %s\n") % logfile);
9211be35a1SLionel Sambuc err_write(F("*** Please report this problem to %s detailing what you were "
9311be35a1SLionel Sambuc "doing before the crash happened; if possible, include the log "
9411be35a1SLionel Sambuc "file mentioned above\n") % PACKAGE_BUGREPORT);
9511be35a1SLionel Sambuc
9611be35a1SLionel Sambuc /// The handler is installed with SA_RESETHAND, so this is safe to do. We
9711be35a1SLionel Sambuc /// really want to call the default handler to generate any possible core
9811be35a1SLionel Sambuc /// dumps.
9911be35a1SLionel Sambuc ::kill(::getpid(), signo);
10011be35a1SLionel Sambuc }
10111be35a1SLionel Sambuc
10211be35a1SLionel Sambuc
10311be35a1SLionel Sambuc /// Installs a handler for a fatal signal representing a crash.
10411be35a1SLionel Sambuc ///
10511be35a1SLionel Sambuc /// When the specified signal is captured, the crash_handler() will be called to
10611be35a1SLionel Sambuc /// print some informational details to the user and, later, the signal will be
10711be35a1SLionel Sambuc /// redelivered using the default handler to obtain a core dump.
10811be35a1SLionel Sambuc ///
10911be35a1SLionel Sambuc /// \param signo The fatal signal for which to install a handler.
11011be35a1SLionel Sambuc static void
install_one_crash_handler(const int signo)11111be35a1SLionel Sambuc install_one_crash_handler(const int signo)
11211be35a1SLionel Sambuc {
11311be35a1SLionel Sambuc struct ::sigaction sa;
11411be35a1SLionel Sambuc sa.sa_handler = crash_handler;
11511be35a1SLionel Sambuc sigemptyset(&sa.sa_mask);
11611be35a1SLionel Sambuc sa.sa_flags = SA_RESETHAND;
11711be35a1SLionel Sambuc
11811be35a1SLionel Sambuc if (::sigaction(signo, &sa, NULL) == -1) {
11911be35a1SLionel Sambuc const int original_errno = errno;
12011be35a1SLionel Sambuc LW(F("Could not install crash handler for signal %s: %s") %
12111be35a1SLionel Sambuc signo % std::strerror(original_errno));
12211be35a1SLionel Sambuc } else
12311be35a1SLionel Sambuc LD(F("Installed crash handler for signal %s") % signo);
12411be35a1SLionel Sambuc }
12511be35a1SLionel Sambuc
12611be35a1SLionel Sambuc
12711be35a1SLionel Sambuc /// Returns a textual representation of an assertion type.
12811be35a1SLionel Sambuc ///
12911be35a1SLionel Sambuc /// The textual representation is user facing.
13011be35a1SLionel Sambuc ///
13111be35a1SLionel Sambuc /// \param type The type of the assertion. If the type is unknown for whatever
13211be35a1SLionel Sambuc /// reason, a special message is returned. The code cannot abort in such a
13311be35a1SLionel Sambuc /// case because this code is dealing for assertion errors.
13411be35a1SLionel Sambuc ///
13511be35a1SLionel Sambuc /// \return A textual description of the assertion type.
13611be35a1SLionel Sambuc static std::string
format_type(const utils::assert_type type)13711be35a1SLionel Sambuc format_type(const utils::assert_type type)
13811be35a1SLionel Sambuc {
13911be35a1SLionel Sambuc switch (type) {
14011be35a1SLionel Sambuc case utils::invariant: return "Invariant check failed";
14111be35a1SLionel Sambuc case utils::postcondition: return "Postcondition check failed";
14211be35a1SLionel Sambuc case utils::precondition: return "Precondition check failed";
14311be35a1SLionel Sambuc case utils::unreachable: return "Unreachable point reached";
14411be35a1SLionel Sambuc default: return "UNKNOWN ASSERTION TYPE";
14511be35a1SLionel Sambuc }
14611be35a1SLionel Sambuc }
14711be35a1SLionel Sambuc
14811be35a1SLionel Sambuc
14911be35a1SLionel Sambuc } // anonymous namespace
15011be35a1SLionel Sambuc
15111be35a1SLionel Sambuc
15211be35a1SLionel Sambuc /// Raises an assertion error.
15311be35a1SLionel Sambuc ///
15411be35a1SLionel Sambuc /// This function prints information about the assertion failure and terminates
15511be35a1SLionel Sambuc /// execution immediately by calling std::abort(). This ensures a coredump so
15611be35a1SLionel Sambuc /// that the failure can be analyzed later.
15711be35a1SLionel Sambuc ///
15811be35a1SLionel Sambuc /// \param type The assertion type; this influences the printed message.
15911be35a1SLionel Sambuc /// \param file The file in which the assertion failed.
16011be35a1SLionel Sambuc /// \param line The line in which the assertion failed.
16111be35a1SLionel Sambuc /// \param message The failure message associated to the condition.
16211be35a1SLionel Sambuc void
sanity_failure(const assert_type type,const char * file,const size_t line,const std::string & message)16311be35a1SLionel Sambuc utils::sanity_failure(const assert_type type, const char* file,
16411be35a1SLionel Sambuc const size_t line, const std::string& message)
16511be35a1SLionel Sambuc {
16611be35a1SLionel Sambuc std::cerr << "*** " << file << ":" << line << ": " << format_type(type);
16711be35a1SLionel Sambuc if (!message.empty())
16811be35a1SLionel Sambuc std::cerr << ": " << message << "\n";
16911be35a1SLionel Sambuc else
17011be35a1SLionel Sambuc std::cerr << "\n";
17111be35a1SLionel Sambuc std::abort();
17211be35a1SLionel Sambuc }
17311be35a1SLionel Sambuc
17411be35a1SLionel Sambuc
17511be35a1SLionel Sambuc /// Installs persistent handlers for crash signals.
17611be35a1SLionel Sambuc ///
17711be35a1SLionel Sambuc /// Should be called at the very beginning of the execution of the program to
17811be35a1SLionel Sambuc /// ensure that a signal handler for fatal crash signals is installed.
17911be35a1SLionel Sambuc ///
18011be35a1SLionel Sambuc /// \pre The function has not been called before.
18111be35a1SLionel Sambuc ///
18211be35a1SLionel Sambuc /// \param logfile_ The path to the log file to report during a crash.
18311be35a1SLionel Sambuc void
install_crash_handlers(const std::string & logfile_)18411be35a1SLionel Sambuc utils::install_crash_handlers(const std::string& logfile_)
18511be35a1SLionel Sambuc {
186*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
18711be35a1SLionel Sambuc static bool installed = false;
188*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
18911be35a1SLionel Sambuc PRE(!installed);
19011be35a1SLionel Sambuc logfile = logfile_;
19111be35a1SLionel Sambuc
19211be35a1SLionel Sambuc for (const int* iter = &fatal_signals[0]; *iter != 0; iter++)
19311be35a1SLionel Sambuc install_one_crash_handler(*iter);
19411be35a1SLionel Sambuc
195*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
19611be35a1SLionel Sambuc installed = true;
197*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
19811be35a1SLionel Sambuc }
199