abcdcc7c5c71d848be1b3060ae7c26cf52063a1c
[cvc5.git] / src / main / util.cpp
1 /********************* */
2 /*! \file util.cpp
3 ** \verbatim
4 ** Original author: Morgan Deters
5 ** Major contributors: none
6 ** Minor contributors (to current version): Christopher L. Conway, Tim King, ACSYS
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
11 **
12 ** \brief Utilities for the main driver.
13 **
14 ** Utilities for the main driver.
15 **/
16
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cerrno>
20 #include <exception>
21 #include <string.h>
22
23 #ifndef __WIN32__
24
25 #include <signal.h>
26 #include <sys/resource.h>
27 #include <unistd.h>
28
29 #endif /* __WIN32__ */
30
31 #include "base/exception.h"
32 #include "base/tls.h"
33 #include "cvc4autoconfig.h"
34 #include "main/command_executor.h"
35 #include "main/main.h"
36 #include "options/base_options.h"
37 #include "options/options.h"
38 #include "smt/smt_engine.h"
39 #include "util/statistics.h"
40
41 using CVC4::Exception;
42 using namespace std;
43
44 namespace CVC4 {
45
46 #ifdef CVC4_DEBUG
47 //extern CVC4_THREADLOCAL(const char*) s_debugLastException;
48 #endif /* CVC4_DEBUG */
49
50 namespace main {
51
52 /**
53 * If true, will not spin on segfault even when CVC4_DEBUG is on.
54 * Useful for nightly regressions, noninteractive performance runs
55 * etc.
56 */
57 bool segvSpin = false;
58
59 #ifndef __WIN32__
60
61 size_t cvc4StackSize;
62 void* cvc4StackBase;
63
64 /** Handler for SIGXCPU, i.e., timeout. */
65 void timeout_handler(int sig, siginfo_t* info, void*) {
66 fprintf(stderr, "CVC4 interrupted by timeout.\n");
67 if((*pOptions)[options::statistics] && pExecutor != NULL) {
68 pTotalTime->stop();
69 pExecutor->flushStatistics(cerr);
70 }
71 abort();
72 }
73
74 /** Handler for SIGINT, i.e., when the user hits control C. */
75 void sigint_handler(int sig, siginfo_t* info, void*) {
76 fprintf(stderr, "CVC4 interrupted by user.\n");
77 if((*pOptions)[options::statistics] && pExecutor != NULL) {
78 pTotalTime->stop();
79 pExecutor->flushStatistics(cerr);
80 }
81 abort();
82 }
83
84 /** Handler for SIGSEGV (segfault). */
85 void segv_handler(int sig, siginfo_t* info, void* c) {
86 uintptr_t extent = reinterpret_cast<uintptr_t>(cvc4StackBase) - cvc4StackSize;
87 uintptr_t addr = reinterpret_cast<uintptr_t>(info->si_addr);
88 #ifdef CVC4_DEBUG
89 fprintf(stderr, "CVC4 suffered a segfault in DEBUG mode.\n");
90 cerr << "Offending address is " << info->si_addr << endl;
91 //cerr << "base is " << (void*)cvc4StackBase << endl;
92 //cerr << "size is " << cvc4StackSize << endl;
93 //cerr << "extent is " << (void*)extent << endl;
94 if(addr >= extent && addr <= extent + 10*1024) {
95 cerr << "Looks like this is likely due to stack overflow." << endl
96 << "You might consider increasing the limit with `ulimit -s' or equivalent." << endl;
97 } else if(addr < 10*1024) {
98 cerr << "Looks like a NULL pointer was dereferenced." << endl;
99 }
100
101 if(!segvSpin) {
102 if((*pOptions)[options::statistics] && pExecutor != NULL) {
103 pTotalTime->stop();
104 pExecutor->flushStatistics(cerr);
105 }
106 abort();
107 } else {
108 fprintf(stderr, "Spinning so that a debugger can be connected.\n");
109 cerr << "Try: gdb " << progName << " " << getpid() << endl
110 << " or: gdb --pid=" << getpid() << " " << progName << endl;
111 for(;;) {
112 sleep(60);
113 }
114 }
115 #else /* CVC4_DEBUG */
116 fprintf(stderr, "CVC4 suffered a segfault.\n");
117 cerr << "Offending address is " << info->si_addr << endl;
118 if(addr >= extent && addr <= extent + 10*1024) {
119 cerr << "Looks like this is likely due to stack overflow." << endl
120 << "You might consider increasing the limit with `ulimit -s' or equivalent." << endl;
121 } else if(addr < 10*1024) {
122 cerr << "Looks like a NULL pointer was dereferenced." << endl;
123 }
124 if((*pOptions)[options::statistics] && pExecutor != NULL) {
125 pTotalTime->stop();
126 pExecutor->flushStatistics(cerr);
127 }
128 abort();
129 #endif /* CVC4_DEBUG */
130 }
131
132 /** Handler for SIGILL (illegal instruction). */
133 void ill_handler(int sig, siginfo_t* info, void*) {
134 #ifdef CVC4_DEBUG
135 fprintf(stderr, "CVC4 executed an illegal instruction in DEBUG mode.\n");
136 if(!segvSpin) {
137 if((*pOptions)[options::statistics] && pExecutor != NULL) {
138 pTotalTime->stop();
139 pExecutor->flushStatistics(cerr);
140 }
141 abort();
142 } else {
143 fprintf(stderr, "Spinning so that a debugger can be connected.\n");
144 fprintf(stderr, "Try: gdb %s %u\n", progName, getpid());
145 fprintf(stderr, " or: gdb --pid=%u %s\n", getpid(), progName);
146 for(;;) {
147 sleep(60);
148 }
149 }
150 #else /* CVC4_DEBUG */
151 fprintf(stderr, "CVC4 executed an illegal instruction.\n");
152 if((*pOptions)[options::statistics] && pExecutor != NULL) {
153 pTotalTime->stop();
154 pExecutor->flushStatistics(cerr);
155 }
156 abort();
157 #endif /* CVC4_DEBUG */
158 }
159
160 #endif /* __WIN32__ */
161
162 static terminate_handler default_terminator;
163
164 void cvc4unexpected() {
165 #if defined(CVC4_DEBUG) && !defined(__WIN32__)
166 fprintf(stderr, "\n"
167 "CVC4 threw an \"unexpected\" exception (one that wasn't properly "
168 "specified\nin the throws() specifier for the throwing function)."
169 "\n\n");
170
171 const char* lastContents = LastExceptionBuffer::currentContents();
172
173 if(lastContents == NULL) {
174 fprintf(stderr,
175 "The exception is unknown (maybe it's not a CVC4::Exception).\n\n");
176 } else {
177 fprintf(stderr, "The exception is:\n%s\n\n", lastContents);
178 }
179 if(!segvSpin) {
180 if((*pOptions)[options::statistics] && pExecutor != NULL) {
181 pTotalTime->stop();
182 pExecutor->flushStatistics(cerr);
183 }
184 set_terminate(default_terminator);
185 } else {
186 fprintf(stderr, "Spinning so that a debugger can be connected.\n");
187 fprintf(stderr, "Try: gdb %s %u\n", progName, getpid());
188 fprintf(stderr, " or: gdb --pid=%u %s\n", getpid(), progName);
189 for(;;) {
190 sleep(60);
191 }
192 }
193 #else /* CVC4_DEBUG */
194 fprintf(stderr, "CVC4 threw an \"unexpected\" exception.\n");
195 if((*pOptions)[options::statistics] && pExecutor != NULL) {
196 pTotalTime->stop();
197 pExecutor->flushStatistics(cerr);
198 }
199 set_terminate(default_terminator);
200 #endif /* CVC4_DEBUG */
201 }
202
203 void cvc4terminate() {
204 set_terminate(default_terminator);
205 #ifdef CVC4_DEBUG
206 LastExceptionBuffer* current = LastExceptionBuffer::getCurrent();
207 LastExceptionBuffer::setCurrent(NULL);
208 delete current;
209
210 fprintf(stderr, "\n"
211 "CVC4 was terminated by the C++ runtime.\n"
212 "Perhaps an exception was thrown during stack unwinding. "
213 "(Don't do that.)\n");
214 if((*pOptions)[options::statistics] && pExecutor != NULL) {
215 pTotalTime->stop();
216 pExecutor->flushStatistics(cerr);
217 }
218 default_terminator();
219 #else /* CVC4_DEBUG */
220 fprintf(stderr,
221 "CVC4 was terminated by the C++ runtime.\n"
222 "Perhaps an exception was thrown during stack unwinding.\n");
223 if((*pOptions)[options::statistics] && pExecutor != NULL) {
224 pTotalTime->stop();
225 pExecutor->flushStatistics(cerr);
226 }
227 default_terminator();
228 #endif /* CVC4_DEBUG */
229 }
230
231 /** Initialize the driver. Sets signal handlers for SIGINT and SIGSEGV. */
232 void cvc4_init() throw(Exception) {
233 #ifdef CVC4_DEBUG
234 LastExceptionBuffer::setCurrent(new LastExceptionBuffer());
235 #endif
236
237 #ifndef __WIN32__
238 stack_t ss;
239 ss.ss_sp = malloc(SIGSTKSZ);
240 if(ss.ss_sp == NULL) {
241 throw Exception("Can't malloc() space for a signal stack");
242 }
243 ss.ss_size = SIGSTKSZ;
244 ss.ss_flags = 0;
245 if(sigaltstack(&ss, NULL) == -1) {
246 throw Exception(string("sigaltstack() failure: ") + strerror(errno));
247 }
248 struct rlimit limit;
249 if(getrlimit(RLIMIT_STACK, &limit)) {
250 throw Exception(string("getrlimit() failure: ") + strerror(errno));
251 }
252 if(limit.rlim_cur != limit.rlim_max) {
253 limit.rlim_cur = limit.rlim_max;
254 if(setrlimit(RLIMIT_STACK, &limit)) {
255 throw Exception(string("setrlimit() failure: ") + strerror(errno));
256 }
257 if(getrlimit(RLIMIT_STACK, &limit)) {
258 throw Exception(string("getrlimit() failure: ") + strerror(errno));
259 }
260 }
261 cvc4StackSize = limit.rlim_cur;
262 cvc4StackBase = ss.ss_sp;
263
264 struct sigaction act1;
265 act1.sa_sigaction = sigint_handler;
266 act1.sa_flags = SA_SIGINFO;
267 sigemptyset(&act1.sa_mask);
268 if(sigaction(SIGINT, &act1, NULL)) {
269 throw Exception(string("sigaction(SIGINT) failure: ") + strerror(errno));
270 }
271
272 struct sigaction act2;
273 act2.sa_sigaction = timeout_handler;
274 act2.sa_flags = SA_SIGINFO;
275 sigemptyset(&act2.sa_mask);
276 if(sigaction(SIGXCPU, &act2, NULL)) {
277 throw Exception(string("sigaction(SIGXCPU) failure: ") + strerror(errno));
278 }
279
280 struct sigaction act3;
281 act3.sa_sigaction = segv_handler;
282 act3.sa_flags = SA_SIGINFO | SA_ONSTACK;
283 sigemptyset(&act3.sa_mask);
284 if(sigaction(SIGSEGV, &act3, NULL)) {
285 throw Exception(string("sigaction(SIGSEGV) failure: ") + strerror(errno));
286 }
287
288 struct sigaction act4;
289 act4.sa_sigaction = segv_handler;
290 act4.sa_flags = SA_SIGINFO;
291 sigemptyset(&act4.sa_mask);
292 if(sigaction(SIGILL, &act4, NULL)) {
293 throw Exception(string("sigaction(SIGILL) failure: ") + strerror(errno));
294 }
295
296 #endif /* __WIN32__ */
297
298 set_unexpected(cvc4unexpected);
299 default_terminator = set_terminate(cvc4terminate);
300 }
301
302 void cvc4_shutdown() throw () {
303 #ifndef __WIN32__
304 free(cvc4StackBase);
305 cvc4StackBase = NULL;
306 cvc4StackSize = 0;
307 #endif /* __WIN32__ */
308 }
309
310 }/* CVC4::main namespace */
311 }/* CVC4 namespace */