Skip to content

Commit

Permalink
Add --save-smaller|-U to keep smallest duplicate
Browse files Browse the repository at this point in the history
While --save_all can be used to save all crashes, often people only
really want to find the smallest possible crash file.

This patch adds a --save_smaller option that overwrites the crash file
when it would shrink the file size.

See google#305
  • Loading branch information
douglasbagnall committed Feb 9, 2021
1 parent 97095d7 commit 4958013
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
7 changes: 6 additions & 1 deletion cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
.crashDir = NULL,
.covDirNew = NULL,
.saveUnique = true,
.saveSmaller = false,
.dynfileqMaxSz = 0U,
.dynfileqCnt = 0U,
.dynfileqCurrent = NULL,
Expand Down Expand Up @@ -508,6 +509,7 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
{ { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
{ { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
{ { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
{ { "save_smaller", no_argument, NULL, 'U' }, "Save smaller test-cases, renaming first filename with .orig suffix" },
{ { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Treat time-outs as crashes - use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
{ { "sanitizers", no_argument, NULL, 'S' }, "** DEPRECATED ** Enable sanitizers settings (default: false)" },
{ { "sanitizers_del_report", required_argument, NULL, 0x10F }, "Delete sanitizer report after use (default: false)" },
Expand Down Expand Up @@ -555,7 +557,7 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
int opt_index = 0;
for (;;) {
int c = getopt_long(
argc, argv, "-?hQvVsuPxf:i:o:dqe:W:r:c:F:t:R:n:N:l:p:g:E:w:B:zMTS", opts, &opt_index);
argc, argv, "-?hQvVsuUPxf:i:o:dqe:W:r:c:F:t:R:n:N:l:p:g:E:w:B:zMTS", opts, &opt_index);
if (c < 0) {
break;
}
Expand Down Expand Up @@ -587,6 +589,9 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
case 'u':
hfuzz->io.saveUnique = false;
break;
case 'U':
hfuzz->io.saveSmaller = true;
break;
case 'l':
logfile = optarg;
break;
Expand Down
2 changes: 2 additions & 0 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ Options:
Pass this environment variable, can be used multiple times
--save_all|-u
Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames
--save_smaller|-U
Save smaller test-cases, renaming first found with .orig suffix
--tmout_sigvtalrm|-T
Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)
--sanitizers|-S
Expand Down
1 change: 1 addition & 0 deletions honggfuzz.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ typedef struct {
const char* crashDir;
const char* covDirNew;
bool saveUnique;
bool saveSmaller;
size_t dynfileqMaxSz;
size_t dynfileqCnt;
dynfile_t* dynfileqCurrent;
Expand Down
39 changes: 35 additions & 4 deletions linux/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,10 +703,41 @@ static void arch_traceSaveData(run_t* run, pid_t pid) {
}

if (files_exists(run->crashFileName)) {
LOG_I("Crash (dup): '%s' already exists, skipping", run->crashFileName);
/* Clear filename so that verifier can understand we hit a duplicate */
memset(run->crashFileName, 0, sizeof(run->crashFileName));
return;
if (run->global->io.saveSmaller) {
/*
* If the new run produces a smaller file than exists already, we
* will replace it.
*
* If this is the second test case, we save the first with .orig
* suffix before overwriting.
*/
struct stat st;
char origFile[PATH_MAX];
if (stat(run->crashFileName, &st) == -1) {
LOG_W("Couldn't stat() the '%s' file", run->crashFileName);
} else if (st.st_size <= (off_t)run->dynfile->size) {
LOG_I("Crash (dup): '%s' exists and is smaller, skipping", run->crashFileName);
/* Clear filename so that verifier can understand we hit a duplicate */
memset(run->crashFileName, 0, sizeof(run->crashFileName));
return;
} else {
/* we have a new champion */
LOG_I("Crash: overwriting '%s' (old %zu bytes, new %zu bytes)",
run->crashFileName, (size_t)st.st_size, (size_t)run->dynfile->size);
}

snprintf(origFile, sizeof(origFile), "%s.orig", run->crashFileName);
if (! files_exists(origFile)) {
rename(run->crashFileName, origFile);
} else {
unlink(run->crashFileName);
}
} else {
LOG_I("Crash (dup): '%s' already exists, skipping", run->crashFileName);
/* Clear filename so that verifier can understand we hit a duplicate */
memset(run->crashFileName, 0, sizeof(run->crashFileName));
return;
}
}

if (!files_writeBufToFile(run->crashFileName, run->dynfile->data, run->dynfile->size,
Expand Down

0 comments on commit 4958013

Please sign in to comment.