Implement --tlimit for windows (#4716)
authorGereon Kremer <gereon.kremer@cs.rwth-aachen.de>
Mon, 13 Jul 2020 11:57:41 +0000 (13:57 +0200)
committerGitHub <noreply@github.com>
Mon, 13 Jul 2020 11:57:41 +0000 (06:57 -0500)
The new mechanism for --tlimit only works for POSIX compatible systems (that implement setitimer). This PR implements an alternative (though roughly equivalent) approach for windows, based on SetWaitableTimer().

To make this work (without code duplication) we need to call the timeout_handler function from time_limit.cpp as the windows solution employs an asynchronous callback instead of signals. I used the opportunity to rename util.cpp to signal_handlers.cpp (as it really does not do anything else) and reformat the file.

As I do not have a windows system at hand, I have not been able to actually test this apart from making sure that it compiles with the mingw setup.

src/main/CMakeLists.txt
src/main/driver_unified.cpp
src/main/signal_handlers.cpp [new file with mode: 0644]
src/main/signal_handlers.h [new file with mode: 0644]
src/main/time_limit.cpp
src/main/time_limit.h
src/main/util.cpp [deleted file]

index 723d6346f76a39e4ac0287c7ebb9d638b97ed602..4fbb14183b3d9fe15348ed586c33c36b6ab1a3b3 100644 (file)
@@ -6,9 +6,10 @@ set(libmain_src_files
   interactive_shell.cpp
   interactive_shell.h
   main.h
+  signal_handlers.cpp
+  signal_handlers.h
   time_limit.cpp
   time_limit.h
-  util.cpp
 )
 
 #-----------------------------------------------------------------------------#
index 955fa7b749791de24a92597eae411e76727a4259..b8d845f9e10f9d23513de9d605f1fd7a9c581c28 100644 (file)
@@ -32,6 +32,7 @@
 #include "main/command_executor.h"
 #include "main/interactive_shell.h"
 #include "main/main.h"
+#include "main/signal_handlers.h"
 #include "main/time_limit.h"
 #include "options/options.h"
 #include "options/set_language.h"
@@ -92,7 +93,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
   pOptions = &opts;
 
   // Initialize the signal handlers
-  cvc4_init();
+  signal_handlers::install();
 
   progPath = argv[0];
 
@@ -507,7 +508,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
   pTotalTime = NULL;
   pExecutor = NULL;
 
-  cvc4_shutdown();
+  signal_handlers::cleanup();
 
   return returnValue;
 }
diff --git a/src/main/signal_handlers.cpp b/src/main/signal_handlers.cpp
new file mode 100644 (file)
index 0000000..6f24dfc
--- /dev/null
@@ -0,0 +1,405 @@
+/*********************                                                        */
+/*! \file signal_handlers.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andres Noetzli, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of signal handlers.
+ **
+ ** Implementation of signal handlers.
+ **
+ ** It is important to only call async-signal-safe functions from signal
+ ** handlers. See: http://man7.org/linux/man-pages/man7/signal-safety.7.html for
+ ** a list of async-signal-safe POSIX.1 functions.
+ **/
+
+#include <string.h>
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <exception>
+
+#ifndef __WIN32__
+
+#include <signal.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#endif /* __WIN32__ */
+
+#include "base/exception.h"
+#include "cvc4autoconfig.h"
+#include "main/command_executor.h"
+#include "main/main.h"
+#include "options/options.h"
+#include "smt/smt_engine.h"
+#include "util/safe_print.h"
+#include "util/statistics.h"
+
+using CVC4::Exception;
+using namespace std;
+
+namespace CVC4 {
+namespace main {
+
+/**
+ * If true, will not spin on segfault even when CVC4_DEBUG is on.
+ * Useful for nightly regressions, noninteractive performance runs
+ * etc.
+ */
+bool segvSpin = false;
+
+namespace signal_handlers {
+
+void print_statistics()
+{
+  if (pOptions != NULL && pOptions->getStatistics() && pExecutor != NULL)
+  {
+    if (pTotalTime != NULL && pTotalTime->running())
+    {
+      pTotalTime->stop();
+    }
+    pExecutor->safeFlushStatistics(STDERR_FILENO);
+  }
+}
+
+void timeout_handler()
+{
+  safe_print(STDERR_FILENO, "CVC4 interrupted by timeout.\n");
+  print_statistics();
+  abort();
+}
+
+#ifndef __WIN32__
+
+#ifdef HAVE_SIGALTSTACK
+size_t cvc4StackSize;
+void* cvc4StackBase;
+#endif /* HAVE_SIGALTSTACK */
+
+/** Handler for SIGXCPU and SIGALRM, i.e., timeout. */
+void timeout_handler(int sig, siginfo_t* info, void*) { timeout_handler(); }
+
+/** Handler for SIGTERM. */
+void sigterm_handler(int sig, siginfo_t* info, void*)
+{
+  safe_print(STDERR_FILENO, "CVC4 interrupted by SIGTERM.\n");
+  print_statistics();
+  abort();
+}
+
+/** Handler for SIGINT, i.e., when the user hits control C. */
+void sigint_handler(int sig, siginfo_t* info, void*)
+{
+  safe_print(STDERR_FILENO, "CVC4 interrupted by user.\n");
+  print_statistics();
+  abort();
+}
+
+#ifdef HAVE_SIGALTSTACK
+/** Handler for SIGSEGV (segfault). */
+void segv_handler(int sig, siginfo_t* info, void* c)
+{
+  uintptr_t extent = reinterpret_cast<uintptr_t>(cvc4StackBase) - cvc4StackSize;
+  uintptr_t addr = reinterpret_cast<uintptr_t>(info->si_addr);
+#ifdef CVC4_DEBUG
+  safe_print(STDERR_FILENO, "CVC4 suffered a segfault in DEBUG mode.\n");
+  safe_print(STDERR_FILENO, "Offending address is ");
+  safe_print(STDERR_FILENO, info->si_addr);
+  safe_print(STDERR_FILENO, "\n");
+  // cerr << "base is " << (void*)cvc4StackBase << endl;
+  // cerr << "size is " << cvc4StackSize << endl;
+  // cerr << "extent is " << (void*)extent << endl;
+  if (addr >= extent && addr <= extent + 10 * 1024)
+  {
+    safe_print(STDERR_FILENO,
+               "Looks like this is likely due to stack overflow.\n");
+    safe_print(STDERR_FILENO,
+               "You might consider increasing the limit with `ulimit -s' or "
+               "equivalent.\n");
+  }
+  else if (addr < 10 * 1024)
+  {
+    safe_print(STDERR_FILENO, "Looks like a NULL pointer was dereferenced.\n");
+  }
+
+  if (!segvSpin)
+  {
+    print_statistics();
+    abort();
+  }
+  else
+  {
+    safe_print(STDERR_FILENO,
+               "Spinning so that a debugger can be connected.\n");
+    safe_print(STDERR_FILENO, "Try:  gdb ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, " ");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, "\n");
+    safe_print(STDERR_FILENO, " or:  gdb --pid=");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, " ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, "\n");
+    for (;;)
+    {
+      sleep(60);
+    }
+  }
+#else  /* CVC4_DEBUG */
+  safe_print(STDERR_FILENO, "CVC4 suffered a segfault.\n");
+  safe_print(STDERR_FILENO, "Offending address is ");
+  safe_print(STDERR_FILENO, info->si_addr);
+  safe_print(STDERR_FILENO, "\n");
+  if (addr >= extent && addr <= extent + 10 * 1024)
+  {
+    safe_print(STDERR_FILENO,
+               "Looks like this is likely due to stack overflow.\n");
+    safe_print(STDERR_FILENO,
+               "You might consider increasing the limit with `ulimit -s' or "
+               "equivalent.\n");
+  }
+  else if (addr < 10 * 1024)
+  {
+    safe_print(STDERR_FILENO, "Looks like a NULL pointer was dereferenced.\n");
+  }
+  print_statistics();
+  abort();
+#endif /* CVC4_DEBUG */
+}
+#endif /* HAVE_SIGALTSTACK */
+
+/** Handler for SIGILL (illegal instruction). */
+void ill_handler(int sig, siginfo_t* info, void*)
+{
+#ifdef CVC4_DEBUG
+  safe_print(STDERR_FILENO,
+             "CVC4 executed an illegal instruction in DEBUG mode.\n");
+  if (!segvSpin)
+  {
+    print_statistics();
+    abort();
+  }
+  else
+  {
+    safe_print(STDERR_FILENO,
+               "Spinning so that a debugger can be connected.\n");
+    safe_print(STDERR_FILENO, "Try:  gdb ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, " ");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, "\n");
+    safe_print(STDERR_FILENO, " or:  gdb --pid=");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, " ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, "\n");
+    for (;;)
+    {
+      sleep(60);
+    }
+  }
+#else  /* CVC4_DEBUG */
+  safe_print(STDERR_FILENO, "CVC4 executed an illegal instruction.\n");
+  print_statistics();
+  abort();
+#endif /* CVC4_DEBUG */
+}
+
+#endif /* __WIN32__ */
+
+static terminate_handler default_terminator;
+
+void cvc4unexpected()
+{
+#if defined(CVC4_DEBUG) && !defined(__WIN32__)
+  safe_print(STDERR_FILENO,
+             "\n"
+             "CVC4 threw an \"unexpected\" exception (one that wasn't properly "
+             "specified\nin the throws() specifier for the throwing function)."
+             "\n\n");
+
+  const char* lastContents = LastExceptionBuffer::currentContents();
+
+  if (lastContents == NULL)
+  {
+    safe_print(
+        STDERR_FILENO,
+        "The exception is unknown (maybe it's not a CVC4::Exception).\n\n");
+  }
+  else
+  {
+    safe_print(STDERR_FILENO, "The exception is:\n");
+    safe_print(STDERR_FILENO, lastContents);
+    safe_print(STDERR_FILENO, "\n\n");
+  }
+  if (!segvSpin)
+  {
+    print_statistics();
+    set_terminate(default_terminator);
+  }
+  else
+  {
+    safe_print(STDERR_FILENO,
+               "Spinning so that a debugger can be connected.\n");
+    safe_print(STDERR_FILENO, "Try:  gdb ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, " ");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, "\n");
+    safe_print(STDERR_FILENO, " or:  gdb --pid=");
+    safe_print<int64_t>(STDERR_FILENO, getpid());
+    safe_print(STDERR_FILENO, " ");
+    safe_print(STDERR_FILENO, *progName);
+    safe_print(STDERR_FILENO, "\n");
+    for (;;)
+    {
+      sleep(60);
+    }
+  }
+#else  /* CVC4_DEBUG */
+  safe_print(STDERR_FILENO, "CVC4 threw an \"unexpected\" exception.\n");
+  print_statistics();
+  set_terminate(default_terminator);
+#endif /* CVC4_DEBUG */
+}
+
+void cvc4terminate()
+{
+  set_terminate(default_terminator);
+#ifdef CVC4_DEBUG
+  LastExceptionBuffer* current = LastExceptionBuffer::getCurrent();
+  LastExceptionBuffer::setCurrent(NULL);
+  delete current;
+
+  safe_print(STDERR_FILENO,
+             "\n"
+             "CVC4 was terminated by the C++ runtime.\n"
+             "Perhaps an exception was thrown during stack unwinding.  "
+             "(Don't do that.)\n");
+  print_statistics();
+  default_terminator();
+#else  /* CVC4_DEBUG */
+  safe_print(STDERR_FILENO,
+             "CVC4 was terminated by the C++ runtime.\n"
+             "Perhaps an exception was thrown during stack unwinding.\n");
+  print_statistics();
+  default_terminator();
+#endif /* CVC4_DEBUG */
+}
+
+void install()
+{
+#ifdef CVC4_DEBUG
+  LastExceptionBuffer::setCurrent(new LastExceptionBuffer());
+#endif
+
+#ifndef __WIN32__
+  struct rlimit limit;
+  if (getrlimit(RLIMIT_STACK, &limit))
+  {
+    throw Exception(string("getrlimit() failure: ") + strerror(errno));
+  }
+  if (limit.rlim_cur != limit.rlim_max)
+  {
+    limit.rlim_cur = limit.rlim_max;
+    if (setrlimit(RLIMIT_STACK, &limit))
+    {
+      throw Exception(string("setrlimit() failure: ") + strerror(errno));
+    }
+    if (getrlimit(RLIMIT_STACK, &limit))
+    {
+      throw Exception(string("getrlimit() failure: ") + strerror(errno));
+    }
+  }
+
+  struct sigaction act1;
+  act1.sa_sigaction = sigint_handler;
+  act1.sa_flags = SA_SIGINFO;
+  sigemptyset(&act1.sa_mask);
+  if (sigaction(SIGINT, &act1, NULL))
+  {
+    throw Exception(string("sigaction(SIGINT) failure: ") + strerror(errno));
+  }
+
+  struct sigaction act2;
+  act2.sa_sigaction = timeout_handler;
+  act2.sa_flags = SA_SIGINFO;
+  sigemptyset(&act2.sa_mask);
+  if (sigaction(SIGXCPU, &act2, NULL))
+  {
+    throw Exception(string("sigaction(SIGXCPU) failure: ") + strerror(errno));
+  }
+
+  struct sigaction act3;
+  act3.sa_sigaction = ill_handler;
+  act3.sa_flags = SA_SIGINFO;
+  sigemptyset(&act3.sa_mask);
+  if (sigaction(SIGILL, &act3, NULL))
+  {
+    throw Exception(string("sigaction(SIGILL) failure: ") + strerror(errno));
+  }
+
+#ifdef HAVE_SIGALTSTACK
+  stack_t ss;
+  ss.ss_sp = (char*)malloc(SIGSTKSZ);
+  if (ss.ss_sp == NULL)
+  {
+    throw Exception("Can't malloc() space for a signal stack");
+  }
+  ss.ss_size = SIGSTKSZ;
+  ss.ss_flags = 0;
+  if (sigaltstack(&ss, NULL) == -1)
+  {
+    throw Exception(string("sigaltstack() failure: ") + strerror(errno));
+  }
+
+  cvc4StackSize = limit.rlim_cur;
+  cvc4StackBase = ss.ss_sp;
+
+  struct sigaction act4;
+  act4.sa_sigaction = segv_handler;
+  act4.sa_flags = SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act4.sa_mask);
+  if (sigaction(SIGSEGV, &act4, NULL))
+  {
+    throw Exception(string("sigaction(SIGSEGV) failure: ") + strerror(errno));
+  }
+#endif /* HAVE_SIGALTSTACK */
+
+  struct sigaction act5;
+  act5.sa_sigaction = sigterm_handler;
+  act5.sa_flags = SA_SIGINFO;
+  sigemptyset(&act5.sa_mask);
+  if (sigaction(SIGTERM, &act5, NULL))
+  {
+    throw Exception(string("sigaction(SIGTERM) failure: ") + strerror(errno));
+  }
+
+#endif /* __WIN32__ */
+
+  std::set_unexpected(cvc4unexpected);
+  default_terminator = set_terminate(cvc4terminate);
+}
+
+void cleanup() noexcept
+{
+#ifndef __WIN32__
+#ifdef HAVE_SIGALTSTACK
+  free(cvc4StackBase);
+  cvc4StackBase = NULL;
+  cvc4StackSize = 0;
+#endif /* HAVE_SIGALTSTACK */
+#endif /* __WIN32__ */
+}
+
+}  // namespace signal_handlers
+}  // namespace main
+}  // namespace CVC4
diff --git a/src/main/signal_handlers.h b/src/main/signal_handlers.h
new file mode 100644 (file)
index 0000000..cc19174
--- /dev/null
@@ -0,0 +1,46 @@
+/*********************                                                        */
+/*! \file signal_handlers.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of signal handlers.
+ **
+ ** Implementation of signal handlers.
+ **/
+
+#ifndef CVC4__MAIN__SIGNAL_HANDLERS_H
+#define CVC4__MAIN__SIGNAL_HANDLERS_H
+
+namespace CVC4 {
+namespace main {
+namespace signal_handlers {
+
+/**
+ * Performs last steps before termination due to a timeout.
+ * Prints an appropriate message and solver statistics.
+ */
+void timeout_handler();
+
+/**
+ * Installs (almost) all signal handlers.
+ * A handler for SIGALRM is set in time_limit.cpp.
+ * Also sets callbacks via std::set_unexpected and std:set_terminate.
+ */
+void install();
+
+/**
+ * Performs cleanup related to the signal handlers.
+ */
+void cleanup();
+
+}  // namespace signal_handlers
+}  // namespace main
+}  // namespace CVC4
+
+#endif /* CVC4__MAIN__SIGNAL_HANDLERS_H */
index 973d48f6f2e3498ebda36f93be77fe68d2c662fd..fb07b5523add8feab17a6204351f43db00b87f45 100644 (file)
@@ -1,19 +1,86 @@
+/*********************                                                        */
+/*! \file time_limit.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of time limits.
+ **
+ ** Implementation of time limits that are imposed by the --tlimit option.
+ **/
+
 #include "time_limit.h"
 
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <windows.h>
+#else
+#include <signal.h>
 #include <sys/time.h>
+#endif
 
 #include <cerrno>
 #include <cstring>
 
+#include "signal_handlers.h"
+
 namespace CVC4 {
 namespace main {
 
+#if defined(__MINGW32__) || defined(__MINGW64__)
+void CALLBACK win_timeout_handler(LPVOID lpArg,
+                                  DWORD dwTimerLowValue,
+                                  DWORD dwTimerHighValue)
+{
+  signal_handlers::timeout_handler();
+}
+#else
+void posix_timeout_handler(int sig, siginfo_t* info, void*)
+{
+  signal_handlers::timeout_handler();
+}
+#endif
+
 void install_time_limit(const Options& opts)
 {
   unsigned long ms = opts.getCumulativeTimeLimit();
+  // Skip if no time limit shall be set.
   if (ms == 0) return;
 
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  HANDLE hTimer = CreateWaitableTimer(nullptr, true, TEXT("CVC4::Timeout"));
+  if (hTimer == nullptr)
+  {
+    throw Exception(std::string("CreateWaitableTimer() failure: ")
+                    + std::to_string(GetLastError()));
+  }
+  LARGE_INTEGER liDueTime;
+  liDueTime.LowPart = (DWORD)(ms & 0xFFFFFFFF);
+  liDueTime.HighPart = 0;
+  if (!SetWaitableTimer(
+          hTimer, &liDueTime, 0, win_timeout_handler, nullptr, false))
+  {
+    throw Exception(std::string("SetWaitableTimer() failure: ")
+                    + std::to_string(GetLastError()));
+  }
+#else
+  // Install a signal handler for SIGALRM
+  struct sigaction sact;
+  sact.sa_sigaction = posix_timeout_handler;
+  sact.sa_flags = SA_SIGINFO;
+  sigemptyset(&sact.sa_mask);
+  if (sigaction(SIGALRM, &sact, NULL))
+  {
+    throw Exception(std::string("sigaction(SIGALRM) failure: ")
+                    + strerror(errno));
+  }
+
   // Check https://linux.die.net/man/2/setitimer
+  // Then time is up, the kernel will send a SIGALRM
   struct itimerval timerspec;
   timerspec.it_value.tv_sec = ms / 1000;
   timerspec.it_value.tv_usec = (ms % 1000) * 1000;
@@ -26,6 +93,7 @@ void install_time_limit(const Options& opts)
   {
     throw Exception(std::string("timer_settime() failure: ") + strerror(errno));
   }
+#endif
 }
 
 }  // namespace main
index ba179fea0214d141625b6eaf28bbca14a185596a..4da3e6845a66952529f787d247c20fdce0c393a4 100644 (file)
@@ -1,3 +1,19 @@
+/*********************                                                        */
+/*! \file time_limit.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of time limits.
+ **
+ ** Implementation of time limits that are imposed by the --tlimit option.
+ **/
+
 #ifndef CVC4__MAIN__TIME_LIMIT_H
 #define CVC4__MAIN__TIME_LIMIT_H
 
@@ -10,9 +26,10 @@ namespace main {
  * Installs an overall wall-clock time limit for the solver binary.
  * It retrieves the time limit and creates a POSIX timer (via setitimer()).
  * This timer signals its expiration with an SIGALRM that is handled by
- * timeout_handler() in util.cpp.
+ * timeout_handler() in signal_handler.cpp.
+ * For windows, we use a timer (via SetWaitableTimer()) that uses
+ * timeout_handler() as callback function.
  */
-
 void install_time_limit(const Options& opts);
 
 }  // namespace main
diff --git a/src/main/util.cpp b/src/main/util.cpp
deleted file mode 100644 (file)
index 888cb76..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-/*********************                                                        */
-/*! \file util.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andres Noetzli, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Utilities for the main driver.
- **
- ** Utilities for the main driver.
- **
- ** It is important to only call async-signal-safe functions from signal
- ** handlers. See: http://man7.org/linux/man-pages/man7/signal-safety.7.html for
- ** a list of async-signal-safe POSIX.1 functions.
- **/
-
-#include <string.h>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <exception>
-
-#ifndef __WIN32__
-
-#include <signal.h>
-#include <sys/resource.h>
-#include <unistd.h>
-
-#endif /* __WIN32__ */
-
-#include "base/exception.h"
-#include "cvc4autoconfig.h"
-#include "main/command_executor.h"
-#include "main/main.h"
-#include "options/options.h"
-#include "smt/smt_engine.h"
-#include "util/safe_print.h"
-#include "util/statistics.h"
-
-using CVC4::Exception;
-using namespace std;
-
-namespace CVC4 {
-namespace main {
-
-/**
- * If true, will not spin on segfault even when CVC4_DEBUG is on.
- * Useful for nightly regressions, noninteractive performance runs
- * etc.
- */
-bool segvSpin = false;
-
-void print_statistics() {
-  if (pOptions != NULL && pOptions->getStatistics() && pExecutor != NULL) {
-    if (pTotalTime != NULL && pTotalTime->running()) {
-      pTotalTime->stop();
-    }
-    pExecutor->safeFlushStatistics(STDERR_FILENO);
-  }
-}
-
-#ifndef __WIN32__
-
-#ifdef HAVE_SIGALTSTACK
-size_t cvc4StackSize;
-void* cvc4StackBase;
-#endif /* HAVE_SIGALTSTACK */
-
-/** Handler for SIGXCPU and SIGALRM, i.e., timeout. */
-void timeout_handler(int sig, siginfo_t* info, void*) {
-  safe_print(STDERR_FILENO, "CVC4 interrupted by timeout.\n");
-  print_statistics();
-  abort();
-}
-
-/** Handler for SIGTERM. */
-void sigterm_handler(int sig, siginfo_t* info, void*)
-{
-  safe_print(STDERR_FILENO, "CVC4 interrupted by SIGTERM.\n");
-  print_statistics();
-  abort();
-}
-
-/** Handler for SIGINT, i.e., when the user hits control C. */
-void sigint_handler(int sig, siginfo_t* info, void*) {
-  safe_print(STDERR_FILENO, "CVC4 interrupted by user.\n");
-  print_statistics();
-  abort();
-}
-
-#ifdef HAVE_SIGALTSTACK
-/** Handler for SIGSEGV (segfault). */
-void segv_handler(int sig, siginfo_t* info, void* c) {
-  uintptr_t extent = reinterpret_cast<uintptr_t>(cvc4StackBase) - cvc4StackSize;
-  uintptr_t addr = reinterpret_cast<uintptr_t>(info->si_addr);
-#ifdef CVC4_DEBUG
-  safe_print(STDERR_FILENO, "CVC4 suffered a segfault in DEBUG mode.\n");
-  safe_print(STDERR_FILENO, "Offending address is ");
-  safe_print(STDERR_FILENO, info->si_addr);
-  safe_print(STDERR_FILENO, "\n");
-  //cerr << "base is " << (void*)cvc4StackBase << endl;
-  //cerr << "size is " << cvc4StackSize << endl;
-  //cerr << "extent is " << (void*)extent << endl;
-  if(addr >= extent && addr <= extent + 10*1024) {
-    safe_print(STDERR_FILENO,
-               "Looks like this is likely due to stack overflow.\n");
-    safe_print(STDERR_FILENO,
-               "You might consider increasing the limit with `ulimit -s' or "
-               "equivalent.\n");
-  } else if(addr < 10*1024) {
-    safe_print(STDERR_FILENO, "Looks like a NULL pointer was dereferenced.\n");
-  }
-
-  if(!segvSpin) {
-    print_statistics();
-    abort();
-  } else {
-    safe_print(STDERR_FILENO,
-               "Spinning so that a debugger can be connected.\n");
-    safe_print(STDERR_FILENO, "Try:  gdb ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, " ");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, "\n");
-    safe_print(STDERR_FILENO, " or:  gdb --pid=");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, " ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, "\n");
-    for(;;) {
-      sleep(60);
-    }
-  }
-#else /* CVC4_DEBUG */
-  safe_print(STDERR_FILENO, "CVC4 suffered a segfault.\n");
-  safe_print(STDERR_FILENO, "Offending address is ");
-  safe_print(STDERR_FILENO, info->si_addr);
-  safe_print(STDERR_FILENO, "\n");
-  if(addr >= extent && addr <= extent + 10*1024) {
-    safe_print(STDERR_FILENO,
-               "Looks like this is likely due to stack overflow.\n");
-    safe_print(STDERR_FILENO,
-               "You might consider increasing the limit with `ulimit -s' or "
-               "equivalent.\n");
-  } else if(addr < 10*1024) {
-    safe_print(STDERR_FILENO, "Looks like a NULL pointer was dereferenced.\n");
-  }
-  print_statistics();
-  abort();
-#endif /* CVC4_DEBUG */
-}
-#endif /* HAVE_SIGALTSTACK */
-
-/** Handler for SIGILL (illegal instruction). */
-void ill_handler(int sig, siginfo_t* info, void*) {
-#ifdef CVC4_DEBUG
-  safe_print(STDERR_FILENO,
-             "CVC4 executed an illegal instruction in DEBUG mode.\n");
-  if(!segvSpin) {
-    print_statistics();
-    abort();
-  } else {
-    safe_print(STDERR_FILENO,
-               "Spinning so that a debugger can be connected.\n");
-    safe_print(STDERR_FILENO, "Try:  gdb ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, " ");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, "\n");
-    safe_print(STDERR_FILENO, " or:  gdb --pid=");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, " ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, "\n");
-    for(;;) {
-      sleep(60);
-    }
-  }
-#else /* CVC4_DEBUG */
-  safe_print(STDERR_FILENO, "CVC4 executed an illegal instruction.\n");
-  print_statistics();
-  abort();
-#endif /* CVC4_DEBUG */
-}
-
-#endif /* __WIN32__ */
-
-static terminate_handler default_terminator;
-
-void cvc4unexpected() {
-#if defined(CVC4_DEBUG) && !defined(__WIN32__)
-  safe_print(STDERR_FILENO,
-             "\n"
-             "CVC4 threw an \"unexpected\" exception (one that wasn't properly "
-             "specified\nin the throws() specifier for the throwing function)."
-             "\n\n");
-
-  const char* lastContents = LastExceptionBuffer::currentContents();
-
-  if(lastContents == NULL) {
-    safe_print(
-        STDERR_FILENO,
-        "The exception is unknown (maybe it's not a CVC4::Exception).\n\n");
-  } else {
-    safe_print(STDERR_FILENO, "The exception is:\n");
-    safe_print(STDERR_FILENO, lastContents);
-    safe_print(STDERR_FILENO, "\n\n");
-  }
-  if(!segvSpin) {
-    print_statistics();
-    set_terminate(default_terminator);
-  } else {
-    safe_print(STDERR_FILENO,
-               "Spinning so that a debugger can be connected.\n");
-    safe_print(STDERR_FILENO, "Try:  gdb ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, " ");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, "\n");
-    safe_print(STDERR_FILENO, " or:  gdb --pid=");
-    safe_print<int64_t>(STDERR_FILENO, getpid());
-    safe_print(STDERR_FILENO, " ");
-    safe_print(STDERR_FILENO, *progName);
-    safe_print(STDERR_FILENO, "\n");
-    for(;;) {
-      sleep(60);
-    }
-  }
-#else /* CVC4_DEBUG */
-  safe_print(STDERR_FILENO, "CVC4 threw an \"unexpected\" exception.\n");
-  print_statistics();
-  set_terminate(default_terminator);
-#endif /* CVC4_DEBUG */
-}
-
-void cvc4terminate() {
-  set_terminate(default_terminator);
-#ifdef CVC4_DEBUG
-  LastExceptionBuffer* current = LastExceptionBuffer::getCurrent();
-  LastExceptionBuffer::setCurrent(NULL);
-  delete current;
-
-  safe_print(STDERR_FILENO,
-             "\n"
-             "CVC4 was terminated by the C++ runtime.\n"
-             "Perhaps an exception was thrown during stack unwinding.  "
-             "(Don't do that.)\n");
-  print_statistics();
-  default_terminator();
-#else /* CVC4_DEBUG */
-  safe_print(STDERR_FILENO,
-             "CVC4 was terminated by the C++ runtime.\n"
-             "Perhaps an exception was thrown during stack unwinding.\n");
-  print_statistics();
-  default_terminator();
-#endif /* CVC4_DEBUG */
-}
-
-/** Initialize the driver.  Sets signal handlers for SIGINT and SIGSEGV. */
-void cvc4_init()
-{
-#ifdef CVC4_DEBUG
-  LastExceptionBuffer::setCurrent(new LastExceptionBuffer());
-#endif
-
-#ifndef __WIN32__
-  struct rlimit limit;
-  if(getrlimit(RLIMIT_STACK, &limit)) {
-    throw Exception(string("getrlimit() failure: ") + strerror(errno));
-  }
-  if(limit.rlim_cur != limit.rlim_max) {
-    limit.rlim_cur = limit.rlim_max;
-    if(setrlimit(RLIMIT_STACK, &limit)) {
-      throw Exception(string("setrlimit() failure: ") + strerror(errno));
-    }
-    if(getrlimit(RLIMIT_STACK, &limit)) {
-      throw Exception(string("getrlimit() failure: ") + strerror(errno));
-    }
-  }
-
-  struct sigaction act1;
-  act1.sa_sigaction = sigint_handler;
-  act1.sa_flags = SA_SIGINFO;
-  sigemptyset(&act1.sa_mask);
-  if(sigaction(SIGINT, &act1, NULL)) {
-    throw Exception(string("sigaction(SIGINT) failure: ") + strerror(errno));
-  }
-
-  struct sigaction act2;
-  act2.sa_sigaction = timeout_handler;
-  act2.sa_flags = SA_SIGINFO;
-  sigemptyset(&act2.sa_mask);
-  if(sigaction(SIGXCPU, &act2, NULL)) {
-    throw Exception(string("sigaction(SIGXCPU) failure: ") + strerror(errno));
-  }
-
-  struct sigaction act2b;
-  act2b.sa_sigaction = timeout_handler;
-  act2b.sa_flags = SA_SIGINFO;
-  sigemptyset(&act2b.sa_mask);
-  if(sigaction(SIGALRM, &act2b, NULL)) {
-    throw Exception(string("sigaction(SIGALRM) failure: ") + strerror(errno));
-  }
-
-  struct sigaction act3;
-  act3.sa_sigaction = ill_handler;
-  act3.sa_flags = SA_SIGINFO;
-  sigemptyset(&act3.sa_mask);
-  if(sigaction(SIGILL, &act3, NULL)) {
-    throw Exception(string("sigaction(SIGILL) failure: ") + strerror(errno));
-  }
-
-#ifdef HAVE_SIGALTSTACK
-  stack_t ss;
-  ss.ss_sp = (char*) malloc(SIGSTKSZ);
-  if(ss.ss_sp == NULL) {
-    throw Exception("Can't malloc() space for a signal stack");
-  }
-  ss.ss_size = SIGSTKSZ;
-  ss.ss_flags = 0;
-  if(sigaltstack(&ss, NULL) == -1) {
-    throw Exception(string("sigaltstack() failure: ") + strerror(errno));
-  }
-
-  cvc4StackSize = limit.rlim_cur;
-  cvc4StackBase = ss.ss_sp;
-
-  struct sigaction act4;
-  act4.sa_sigaction = segv_handler;
-  act4.sa_flags = SA_SIGINFO | SA_ONSTACK;
-  sigemptyset(&act4.sa_mask);
-  if(sigaction(SIGSEGV, &act4, NULL)) {
-    throw Exception(string("sigaction(SIGSEGV) failure: ") + strerror(errno));
-  }
-#endif /* HAVE_SIGALTSTACK */
-
-  struct sigaction act5;
-  act5.sa_sigaction = sigterm_handler;
-  act5.sa_flags = SA_SIGINFO;
-  sigemptyset(&act5.sa_mask);
-  if (sigaction(SIGTERM, &act5, NULL))
-  {
-    throw Exception(string("sigaction(SIGTERM) failure: ") + strerror(errno));
-  }
-
-#endif /* __WIN32__ */
-
-  set_unexpected(cvc4unexpected);
-  default_terminator = set_terminate(cvc4terminate);
-}
-
-void cvc4_shutdown() noexcept
-{
-#ifndef __WIN32__
-#ifdef HAVE_SIGALTSTACK
-  free(cvc4StackBase);
-  cvc4StackBase = NULL;
-  cvc4StackSize = 0;
-#endif /* HAVE_SIGALTSTACK */
-#endif /* __WIN32__ */
-}
-
-}/* CVC4::main namespace */
-}/* CVC4 namespace */