1 /********************* */
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
12 ** \brief Utilities for the main driver.
14 ** Utilities for the main driver.
26 #include <sys/resource.h>
29 #endif /* __WIN32__ */
31 #include "base/exception.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"
41 using CVC4::Exception
;
47 //extern CVC4_THREADLOCAL(const char*) s_debugLastException;
48 #endif /* CVC4_DEBUG */
53 * If true, will not spin on segfault even when CVC4_DEBUG is on.
54 * Useful for nightly regressions, noninteractive performance runs
57 bool segvSpin
= false;
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
) {
69 pExecutor
->flushStatistics(cerr
);
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
) {
79 pExecutor
->flushStatistics(cerr
);
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
);
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
;
102 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
104 pExecutor
->flushStatistics(cerr
);
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
;
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
;
124 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
126 pExecutor
->flushStatistics(cerr
);
129 #endif /* CVC4_DEBUG */
132 /** Handler for SIGILL (illegal instruction). */
133 void ill_handler(int sig
, siginfo_t
* info
, void*) {
135 fprintf(stderr
, "CVC4 executed an illegal instruction in DEBUG mode.\n");
137 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
139 pExecutor
->flushStatistics(cerr
);
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
);
150 #else /* CVC4_DEBUG */
151 fprintf(stderr
, "CVC4 executed an illegal instruction.\n");
152 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
154 pExecutor
->flushStatistics(cerr
);
157 #endif /* CVC4_DEBUG */
160 #endif /* __WIN32__ */
162 static terminate_handler default_terminator
;
164 void cvc4unexpected() {
165 #if defined(CVC4_DEBUG) && !defined(__WIN32__)
167 "CVC4 threw an \"unexpected\" exception (one that wasn't properly "
168 "specified\nin the throws() specifier for the throwing function)."
171 const char* lastContents
= LastExceptionBuffer::currentContents();
173 if(lastContents
== NULL
) {
175 "The exception is unknown (maybe it's not a CVC4::Exception).\n\n");
177 fprintf(stderr
, "The exception is:\n%s\n\n", lastContents
);
180 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
182 pExecutor
->flushStatistics(cerr
);
184 set_terminate(default_terminator
);
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
);
193 #else /* CVC4_DEBUG */
194 fprintf(stderr
, "CVC4 threw an \"unexpected\" exception.\n");
195 if((*pOptions
)[options::statistics
] && pExecutor
!= NULL
) {
197 pExecutor
->flushStatistics(cerr
);
199 set_terminate(default_terminator
);
200 #endif /* CVC4_DEBUG */
203 void cvc4terminate() {
204 set_terminate(default_terminator
);
206 LastExceptionBuffer
* current
= LastExceptionBuffer::getCurrent();
207 LastExceptionBuffer::setCurrent(NULL
);
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
) {
216 pExecutor
->flushStatistics(cerr
);
218 default_terminator();
219 #else /* CVC4_DEBUG */
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
) {
225 pExecutor
->flushStatistics(cerr
);
227 default_terminator();
228 #endif /* CVC4_DEBUG */
231 /** Initialize the driver. Sets signal handlers for SIGINT and SIGSEGV. */
232 void cvc4_init() throw(Exception
) {
234 LastExceptionBuffer::setCurrent(new LastExceptionBuffer());
239 ss
.ss_sp
= malloc(SIGSTKSZ
);
240 if(ss
.ss_sp
== NULL
) {
241 throw Exception("Can't malloc() space for a signal stack");
243 ss
.ss_size
= SIGSTKSZ
;
245 if(sigaltstack(&ss
, NULL
) == -1) {
246 throw Exception(string("sigaltstack() failure: ") + strerror(errno
));
249 if(getrlimit(RLIMIT_STACK
, &limit
)) {
250 throw Exception(string("getrlimit() failure: ") + strerror(errno
));
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
));
257 if(getrlimit(RLIMIT_STACK
, &limit
)) {
258 throw Exception(string("getrlimit() failure: ") + strerror(errno
));
261 cvc4StackSize
= limit
.rlim_cur
;
262 cvc4StackBase
= ss
.ss_sp
;
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
));
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
));
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
));
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
));
296 #endif /* __WIN32__ */
298 set_unexpected(cvc4unexpected
);
299 default_terminator
= set_terminate(cvc4terminate
);
302 void cvc4_shutdown() throw () {
305 cvc4StackBase
= NULL
;
307 #endif /* __WIN32__ */
310 }/* CVC4::main namespace */
311 }/* CVC4 namespace */