Skip to content

Commit

Permalink
Add initial support for crash backtracing
Browse files Browse the repository at this point in the history
  • Loading branch information
ex0dus-0x committed Dec 18, 2019
1 parent 6f49613 commit 862c725
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 7 deletions.
36 changes: 35 additions & 1 deletion src/include/deepstate/DeepState.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <time.h>
#include <unistd.h>
#include <fnmatch.h>
#include <execinfo.h>

#include <deepstate/Log.h>
#include <deepstate/Compiler.h>
Expand Down Expand Up @@ -90,6 +91,7 @@ DECLARE_bool(fork);
DECLARE_bool(list_tests);
DECLARE_bool(boring_only);
DECLARE_bool(run_disabled);
DECLARE_bool(verbose_crash_trace);

DECLARE_int(min_log_level);
DECLARE_int(seed);
Expand Down Expand Up @@ -521,6 +523,25 @@ extern void DeepState_SaveFailingTest(void);
/* Save a crashing test to the output test directory. */
extern void DeepState_SaveCrashingTest(void);

/* Emit test function backtrace after test crashes. */
static void DeepState_EmitBacktrace(int signum, siginfo_t *sig, void *context) {

DeepState_LogFormat(DeepState_LogInfo, "Test crashed with: %s", sys_siglist[sig->si_status]);

void *array[10];
size_t size;
char **strings;

size = backtrace(array, 10);
strings = backtrace_symbols(array, size);

for (size_t i = 0; i < size; i++)
DeepState_LogFormat(DeepState_LogTrace, "%s", strings[i]);

free(strings);
}


/* Jump buffer for returning to `DeepState_Run`. */
extern jmp_buf DeepState_ReturnToRun;

Expand Down Expand Up @@ -650,7 +671,6 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) {
#if defined(__cplusplus) && defined(__cpp_exceptions)
try {
#endif /* __cplusplus */

test->test_func(); /* Run the test function. */
return(DeepState_TestRunPass);

Expand Down Expand Up @@ -692,6 +712,19 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) {
/* Fork and run `test`. */
static enum DeepState_TestRunResult
DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) {

/* If flag is set, install a signal handler for SIGCHLD */
/* TODO(alan): use handler as "multiplexer" and handle child signal */
if (FLAGS_verbose_crash_trace) {
struct sigaction sigact, oldact;

sigact.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
sigact.sa_sigaction = DeepState_EmitBacktrace;

sigaction(SIGCHLD, &sigact, &oldact);
}


pid_t test_pid;
if (FLAGS_fork) {
test_pid = fork();
Expand Down Expand Up @@ -754,6 +787,7 @@ DeepState_RunSavedTestCase(struct DeepState_TestInfo *test, const char *dir,
DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name);
DeepState_LogFormat(DeepState_LogError, "Test case %s crashed", path);
free(path);

if (HAS_FLAG_output_test_dir) {
DeepState_SaveCrashingTest();
}
Expand Down
14 changes: 8 additions & 6 deletions src/lib/DeepState.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ DEFINE_string(output_test_dir, InputOutputGroup, "", "Directory where tests will
DEFINE_bool(take_over, ExecutionGroup, false, "Replay test cases in take-over mode.");
DEFINE_bool(abort_on_fail, ExecutionGroup, false, "Abort on file replay failure (useful in file fuzzing).");
DEFINE_bool(exit_on_fail, ExecutionGroup, false, "Exit with status 255 on test failure.");
DEFINE_bool(verbose_reads, ExecutionGroup, false, "Report on bytes being read during execution of test.");
DEFINE_int(min_log_level, ExecutionGroup, 0, "Minimum level of logging to output (default 2, 0=debug, 1=trace, 2=info, ...).");
DEFINE_int(timeout, ExecutionGroup, 120, "Timeout for brute force fuzzing.");
DEFINE_uint(num_workers, ExecutionGroup, 1, "Number of workers to spawn for testing and test generation.");
DEFINE_bool(verbose_reads, ExecutionGroup, false, "Report on bytes being read during execution of test.");
DEFINE_bool(verbose_crash_trace, ExecutionGroup, false, "If test crashes, report an execution backtrace after abrupt exit.");

/* Fuzzing and symex related options, baked in to perform analysis-related tasks without auxiliary tools */
DEFINE_bool(fuzz, AnalysisGroup, false, "Perform brute force unguided fuzzing.");
Expand Down Expand Up @@ -254,7 +255,7 @@ void DeepState_SwarmAssignCStr_C(const char* file, unsigned line, int stype,
if (NULL == str) {
DeepState_Abandon("Attempted to populate null pointer.");
}
char swarm_allowed[256];
char swarm_allowed[256];
if (allowed == 0) {
/* In swarm mode, if there is no allowed string, create one over all chars. */
for (int i = 0; i < 255; i++) {
Expand Down Expand Up @@ -306,7 +307,7 @@ char *DeepState_SwarmCStr_C(const char* file, unsigned line, int stype,
if (NULL == str) {
DeepState_Abandon("Can't allocate memory");
}
char swarm_allowed[256];
char swarm_allowed[256];
if (allowed == 0) {
/* In swarm mode, if there is no allowed string, create one over all chars. */
for (int i = 0; i < 255; i++) {
Expand Down Expand Up @@ -347,14 +348,14 @@ void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) {
void DeepState_SwarmSymbolizeCStr_C(const char* file, unsigned line, int stype,
char *begin, const char* allowed) {
if (begin && begin[0]) {
char swarm_allowed[256];
char swarm_allowed[256];
if (allowed == 0) {
/* In swarm mode, if there is no allowed string, create one over all chars. */
for (int i = 0; i < 255; i++) {
swarm_allowed[i] = i+1;
}
swarm_allowed[255] = 0;
allowed = (const char*)&swarm_allowed;
allowed = (const char*)&swarm_allowed;
}
uint32_t allowed_size = strlen(allowed);
struct DeepState_SwarmConfig* sc = DeepState_GetSwarmConfig(allowed_size, file, line, stype);
Expand Down Expand Up @@ -668,7 +669,7 @@ extern void DeepState_CleanUp() {
free(DeepState_GeneratedStrings[i]);
}
DeepState_GeneratedStringsIndex = 0;

for (int i = 0; i < DeepState_SwarmConfigsIndex; i++) {
free(DeepState_SwarmConfigs[i]->file);
free(DeepState_SwarmConfigs[i]->fmap);
Expand Down Expand Up @@ -1116,6 +1117,7 @@ enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo

enum DeepState_TestRunResult result = DeepState_ForkAndRunTest(test);


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

Expand Down

0 comments on commit 862c725

Please sign in to comment.