Skip to content

Commit c2a602a

Browse files
committed
Refactor signal handling code: prepare for demangling names, handle SIGINT w/o backtrace, remove our own signal handler frames from backtrace
1 parent 4cad45e commit c2a602a

1 file changed

Lines changed: 134 additions & 28 deletions

File tree

cli/cppcheckexecutor.cpp

Lines changed: 134 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#if defined(__GNUC__)
3636
#define USE_UNIX_SIGNAL_HANDLING
3737
#include <execinfo.h>
38+
#include <cxxabi.h>
3839
#endif
3940

4041
#ifdef USE_UNIX_SIGNAL_HANDLING
@@ -179,45 +180,146 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
179180
}
180181

181182
#if defined(USE_UNIX_SIGNAL_HANDLING)
182-
extern "C" void MySignalHandler(int signo, siginfo_t *info, void *context);
183-
184183
/* (declare this list here, so it may be used in signal handlers in addition to main())
185184
* A list of signals available in ISO C
186185
* Check out http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
187186
* For now we only want to detect abnormal behaviour for a few selected signals:
188187
*/
189-
static const int listofsignals[] = {
190-
/* don't care: SIGABRT, */
191-
SIGFPE,
192-
SIGILL,
193-
SIGINT,
194-
SIGSEGV,
195-
/* don't care: SIGTERM */
188+
struct Signaltype {
189+
int signalnumber;
190+
const char *signalname;
191+
};
192+
#define DECLARE_SIGNAL(x) {x, #x}
193+
static const Signaltype listofsignals[] = {
194+
// don't care: SIGABRT,
195+
DECLARE_SIGNAL(SIGFPE),
196+
DECLARE_SIGNAL(SIGILL),
197+
DECLARE_SIGNAL(SIGINT),
198+
DECLARE_SIGNAL(SIGSEGV),
199+
// don't care: SIGTERM
196200
};
197201

198-
static void print_stacktrace(FILE* f)
202+
// Simple helper function
203+
template<typename T, int size>
204+
int GetArrayLength(T(&)[size])
205+
{
206+
return size;
207+
}
208+
209+
210+
/*
211+
* Try to print the callstack.
212+
* That is very sensitive to the operating system, hardware, compiler and runtime!
213+
*/
214+
static void print_stacktrace(FILE* f, bool demangling)
199215
{
200216
#if defined(__GNUC__)
201217
void *array[50]= {0};
202-
size_t size = backtrace(array, int(sizeof(array)/sizeof(array[0])));
203-
char **strings = backtrace_symbols(array, (int)size);
204-
fprintf(f, "Callstack:\n");
205-
for (std::size_t i = 0; i < size; i++) {
206-
fprintf(f, "%s\n", strings[i]);
218+
const int depth = backtrace(array, (int)GetArrayLength(array));
219+
char **symbolstrings = backtrace_symbols(array, depth);
220+
if (symbolstrings) {
221+
fprintf(f, "Callstack:\n");
222+
const int offset=3; // the first two entries are simply within our own exception handling code, third is within libc
223+
for (int i = offset; i < depth; ++i) {
224+
const char * const symbol = symbolstrings[i];
225+
char * realname = nullptr;
226+
const char * const firstBracket = strchr(symbol, '(');
227+
if (demangling && firstBracket) {
228+
const char * const plus = strchr(firstBracket, '+');
229+
if (plus) {
230+
char input_buffer[512]= {0};
231+
strncpy(input_buffer, firstBracket+1, plus-firstBracket-1);
232+
char output_buffer[1024]= {0};
233+
size_t length = GetArrayLength(output_buffer);
234+
int status=0;
235+
realname = abi::__cxa_demangle(input_buffer, output_buffer, &length, &status); // non-NULL on success
236+
}
237+
}
238+
239+
fprintf(f, "%d. %s\n",
240+
i-offset, (realname) ? realname : symbolstrings[i]);
241+
}
242+
free(symbolstrings);
243+
} else {
244+
fprintf(f, "Callstack could not be obtained\n");
207245
}
208-
free(strings);
209246
#endif
210247
}
211248

212-
void MySignalHandler(int signo, siginfo_t * /*info*/, void * /*context*/)
249+
/*
250+
* Simple mapping
251+
*/
252+
static const char *signal_name(int signo)
213253
{
214-
fprintf(stderr, "Internal error (caught signal %d). Please report this to the cppcheck developers!\n",
215-
signo);
216-
print_stacktrace(stderr);
254+
for (size_t s=0; s<GetArrayLength(listofsignals); ++s) {
255+
if (listofsignals[s].signalnumber==signo)
256+
return listofsignals[s].signalname;
257+
}
258+
return "";
259+
}
260+
261+
/*
262+
* Entry pointer for signal handlers
263+
*/
264+
static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*/)
265+
{
266+
const char * const signame=signal_name(signo);
267+
bool bPrintCallstack=true;
268+
switch (signo) {
269+
case SIGILL:
270+
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
271+
signo, signame, info->si_addr);
272+
break;
273+
case SIGFPE:
274+
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
275+
signo, signame, info->si_addr);
276+
break;
277+
case SIGSEGV:
278+
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
279+
signo, signame, info->si_addr);
280+
break;
281+
/*
282+
case SIGBUS:
283+
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
284+
signo, signame, info->si_addr);
285+
break;
286+
case SIGTRAP:
287+
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
288+
signo, signame, info->si_addr);
289+
break;
290+
*/
291+
case SIGINT:
292+
bPrintCallstack=false;
293+
break;
294+
default:
295+
fprintf(stderr, "Internal error (caught signal %d)\n",
296+
signo);
297+
break;
298+
}
299+
if (bPrintCallstack) {
300+
print_stacktrace(stderr, false);
301+
fprintf(stderr, "Please report this to the cppcheck developers!\n");
302+
}
217303
abort();
218304
}
219305
#endif
220306

307+
#ifdef _MSC_VER
308+
/*
309+
* Any evaluation of the information about the exception needs to be done here!
310+
*/
311+
static int filterException(int code, PEXCEPTION_POINTERS ex)
312+
{
313+
// TODO we should try to extract some information here.
314+
return EXCEPTION_EXECUTE_HANDLER;
315+
}
316+
#endif
317+
318+
/**
319+
* Signal/SEH handling
320+
* TODO Check for multi-threading issues!
321+
*
322+
*/
221323
int CppCheckExecutor::check_wrapper(CppCheck& cppCheck, int argc, const char* const argv[])
222324
{
223325
#ifdef _MSC_VER
@@ -226,17 +328,21 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppCheck, int argc, const char* co
226328
*/
227329
return check_internal(cppCheck, argc, argv);
228330
/*
229-
}
230-
except() {
231-
return -1;
232-
}
331+
}
332+
__except(filterException(GetExceptionCode(), GetExceptionInformation())) {
333+
// reporting to stdout may not be helpful within a GUI application..
334+
fprintf(stderr, "Internal error\n");
335+
fprintf(stderr, "Please report this to the cppcheck developers!\n");
336+
return -1;
337+
}
233338
*/
234339
#elif defined(USE_UNIX_SIGNAL_HANDLING)
235-
struct sigaction act = {0};
340+
struct sigaction act;
341+
memset(&act, 0, sizeof(act));
236342
act.sa_flags=SA_SIGINFO;
237-
act.sa_sigaction=MySignalHandler;
238-
for (std::size_t s=0; s<sizeof(listofsignals)/sizeof(listofsignals[0]); ++s) {
239-
sigaction(listofsignals[s], &act, NULL);
343+
act.sa_sigaction=CppcheckSignalHandler;
344+
for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
345+
sigaction(listofsignals[s].signalnumber, &act, NULL);
240346
}
241347
return check_internal(cppCheck, argc, argv);
242348
#else

0 commit comments

Comments
 (0)