Merge pull request #141 from trailofbits/no_fork_mode

Simple no fork mode for replay and fuzzing
This commit is contained in:
Alex Groce
2018-12-15 14:02:45 -07:00
committed by GitHub
3 changed files with 25 additions and 7 deletions

View File

@@ -115,6 +115,15 @@ argument to see all DeepState options.
DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage.
## A Note on Mac OS and Forking
Normally, when running a test for replay or fuzzing, DeepState forks
in order to cleanly handle crashes of a test. Unfortunately, `fork()`
on mac OS is extremely slow. When using the built-in fuzzer or
replaying tests, it is highly recommended to add the `--no_fork`
option on mac OS, unless you need the added crash handling (that is,
things aren't working without that option).
## Built-In Fuzzer
Every DeepState executable provides a simple built-in fuzzer that

View File

@@ -66,6 +66,7 @@ DECLARE_bool(abort_on_fail);
DECLARE_bool(verbose_reads);
DECLARE_bool(fuzz);
DECLARE_bool(fuzz_save_passing);
DECLARE_bool(no_fork);
DECLARE_int(log_level);
DECLARE_int(seed);
@@ -533,7 +534,7 @@ static void DeepState_RunTest(struct DeepState_TestInfo *test) {
}
/* Run a test case, but in libFuzzer, so not inside a fork. */
static int DeepState_RunTestLLVM(struct DeepState_TestInfo *test) {
static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) {
/* Run the test. */
if (!setjmp(DeepState_ReturnToRun)) {
/* Convert uncaught C++ exceptions into a test failure. */
@@ -577,13 +578,20 @@ static int DeepState_RunTestLLVM(struct DeepState_TestInfo *test) {
/* Fork and run `test`. */
static enum DeepState_TestRunResult
DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) {
pid_t test_pid = fork();
if (!test_pid) {
DeepState_RunTest(test);
pid_t test_pid;
if (!FLAGS_no_fork) {
test_pid = fork();
if (!test_pid) {
DeepState_RunTest(test);
}
}
int wstatus;
waitpid(test_pid, &wstatus, 0);
if (!FLAGS_no_fork) {
waitpid(test_pid, &wstatus, 0);
} else {
wstatus = DeepState_RunTestNoFork(test);
}
/* If we exited normally, the status code tells us if the test passed. */
if (WIFEXITED(wstatus)) {
uint8_t status = WEXITSTATUS(wstatus);

View File

@@ -39,6 +39,7 @@ DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file
DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test.");
DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing.");
DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing.");
DEFINE_bool(no_fork, false, "Don't fork when running a test.");
DEFINE_int(log_level, 0, "Minimum level of logging to output.");
DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set).");
@@ -660,7 +661,7 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DeepState_Begin(test);
enum DeepState_TestRunResult result = DeepState_RunTestLLVM(test);
enum DeepState_TestRunResult result = DeepState_RunTestNoFork(test);
const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL");
if (abort_check != NULL) {