Skip to content

Commit 862c725

Browse files
author
ex0dus-0x
committed
Add initial support for crash backtracing
1 parent 6f49613 commit 862c725

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

src/include/deepstate/DeepState.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <time.h>
3636
#include <unistd.h>
3737
#include <fnmatch.h>
38+
#include <execinfo.h>
3839

3940
#include <deepstate/Log.h>
4041
#include <deepstate/Compiler.h>
@@ -90,6 +91,7 @@ DECLARE_bool(fork);
9091
DECLARE_bool(list_tests);
9192
DECLARE_bool(boring_only);
9293
DECLARE_bool(run_disabled);
94+
DECLARE_bool(verbose_crash_trace);
9395

9496
DECLARE_int(min_log_level);
9597
DECLARE_int(seed);
@@ -521,6 +523,25 @@ extern void DeepState_SaveFailingTest(void);
521523
/* Save a crashing test to the output test directory. */
522524
extern void DeepState_SaveCrashingTest(void);
523525

526+
/* Emit test function backtrace after test crashes. */
527+
static void DeepState_EmitBacktrace(int signum, siginfo_t *sig, void *context) {
528+
529+
DeepState_LogFormat(DeepState_LogInfo, "Test crashed with: %s", sys_siglist[sig->si_status]);
530+
531+
void *array[10];
532+
size_t size;
533+
char **strings;
534+
535+
size = backtrace(array, 10);
536+
strings = backtrace_symbols(array, size);
537+
538+
for (size_t i = 0; i < size; i++)
539+
DeepState_LogFormat(DeepState_LogTrace, "%s", strings[i]);
540+
541+
free(strings);
542+
}
543+
544+
524545
/* Jump buffer for returning to `DeepState_Run`. */
525546
extern jmp_buf DeepState_ReturnToRun;
526547

@@ -650,7 +671,6 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) {
650671
#if defined(__cplusplus) && defined(__cpp_exceptions)
651672
try {
652673
#endif /* __cplusplus */
653-
654674
test->test_func(); /* Run the test function. */
655675
return(DeepState_TestRunPass);
656676

@@ -692,6 +712,19 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) {
692712
/* Fork and run `test`. */
693713
static enum DeepState_TestRunResult
694714
DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) {
715+
716+
/* If flag is set, install a signal handler for SIGCHLD */
717+
/* TODO(alan): use handler as "multiplexer" and handle child signal */
718+
if (FLAGS_verbose_crash_trace) {
719+
struct sigaction sigact, oldact;
720+
721+
sigact.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
722+
sigact.sa_sigaction = DeepState_EmitBacktrace;
723+
724+
sigaction(SIGCHLD, &sigact, &oldact);
725+
}
726+
727+
695728
pid_t test_pid;
696729
if (FLAGS_fork) {
697730
test_pid = fork();
@@ -754,6 +787,7 @@ DeepState_RunSavedTestCase(struct DeepState_TestInfo *test, const char *dir,
754787
DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name);
755788
DeepState_LogFormat(DeepState_LogError, "Test case %s crashed", path);
756789
free(path);
790+
757791
if (HAS_FLAG_output_test_dir) {
758792
DeepState_SaveCrashingTest();
759793
}

src/lib/DeepState.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ DEFINE_string(output_test_dir, InputOutputGroup, "", "Directory where tests will
4141
DEFINE_bool(take_over, ExecutionGroup, false, "Replay test cases in take-over mode.");
4242
DEFINE_bool(abort_on_fail, ExecutionGroup, false, "Abort on file replay failure (useful in file fuzzing).");
4343
DEFINE_bool(exit_on_fail, ExecutionGroup, false, "Exit with status 255 on test failure.");
44-
DEFINE_bool(verbose_reads, ExecutionGroup, false, "Report on bytes being read during execution of test.");
4544
DEFINE_int(min_log_level, ExecutionGroup, 0, "Minimum level of logging to output (default 2, 0=debug, 1=trace, 2=info, ...).");
4645
DEFINE_int(timeout, ExecutionGroup, 120, "Timeout for brute force fuzzing.");
4746
DEFINE_uint(num_workers, ExecutionGroup, 1, "Number of workers to spawn for testing and test generation.");
47+
DEFINE_bool(verbose_reads, ExecutionGroup, false, "Report on bytes being read during execution of test.");
48+
DEFINE_bool(verbose_crash_trace, ExecutionGroup, false, "If test crashes, report an execution backtrace after abrupt exit.");
4849

4950
/* Fuzzing and symex related options, baked in to perform analysis-related tasks without auxiliary tools */
5051
DEFINE_bool(fuzz, AnalysisGroup, false, "Perform brute force unguided fuzzing.");
@@ -254,7 +255,7 @@ void DeepState_SwarmAssignCStr_C(const char* file, unsigned line, int stype,
254255
if (NULL == str) {
255256
DeepState_Abandon("Attempted to populate null pointer.");
256257
}
257-
char swarm_allowed[256];
258+
char swarm_allowed[256];
258259
if (allowed == 0) {
259260
/* In swarm mode, if there is no allowed string, create one over all chars. */
260261
for (int i = 0; i < 255; i++) {
@@ -306,7 +307,7 @@ char *DeepState_SwarmCStr_C(const char* file, unsigned line, int stype,
306307
if (NULL == str) {
307308
DeepState_Abandon("Can't allocate memory");
308309
}
309-
char swarm_allowed[256];
310+
char swarm_allowed[256];
310311
if (allowed == 0) {
311312
/* In swarm mode, if there is no allowed string, create one over all chars. */
312313
for (int i = 0; i < 255; i++) {
@@ -347,14 +348,14 @@ void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) {
347348
void DeepState_SwarmSymbolizeCStr_C(const char* file, unsigned line, int stype,
348349
char *begin, const char* allowed) {
349350
if (begin && begin[0]) {
350-
char swarm_allowed[256];
351+
char swarm_allowed[256];
351352
if (allowed == 0) {
352353
/* In swarm mode, if there is no allowed string, create one over all chars. */
353354
for (int i = 0; i < 255; i++) {
354355
swarm_allowed[i] = i+1;
355356
}
356357
swarm_allowed[255] = 0;
357-
allowed = (const char*)&swarm_allowed;
358+
allowed = (const char*)&swarm_allowed;
358359
}
359360
uint32_t allowed_size = strlen(allowed);
360361
struct DeepState_SwarmConfig* sc = DeepState_GetSwarmConfig(allowed_size, file, line, stype);
@@ -668,7 +669,7 @@ extern void DeepState_CleanUp() {
668669
free(DeepState_GeneratedStrings[i]);
669670
}
670671
DeepState_GeneratedStringsIndex = 0;
671-
672+
672673
for (int i = 0; i < DeepState_SwarmConfigsIndex; i++) {
673674
free(DeepState_SwarmConfigs[i]->file);
674675
free(DeepState_SwarmConfigs[i]->fmap);
@@ -1116,6 +1117,7 @@ enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo
11161117

11171118
enum DeepState_TestRunResult result = DeepState_ForkAndRunTest(test);
11181119

1120+
11191121
if (result == DeepState_TestRunCrash) {
11201122
DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name);
11211123

0 commit comments

Comments
 (0)