Try to clean up fuzzpuzz a bit

I've separated out the various versions of main(), which has helped a
little bit.  I've also stopped using fmemopen() since libFuzzer might
work on Windows.  But I think I probably still have something
fundamentally wrong in my approach.
This commit is contained in:
Ben Harris
2023-02-20 22:53:33 +00:00
parent 5ba227031c
commit 80de73a6aa

View File

@ -23,6 +23,15 @@
* cmake --build build-honggfuzz --target fuzzpuzz * cmake --build build-honggfuzz --target fuzzpuzz
* mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus * mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
* honggfuzz -s -i fuzz-corpus -w fuzzpuzz.dict -- build-honggfuzz/fuzzpuzz * honggfuzz -s -i fuzz-corpus -w fuzzpuzz.dict -- build-honggfuzz/fuzzpuzz
*
* You can also use libFuzzer, though it's not really a good fit for
* Puzzles. The experimental forking mode seems to work OK:
*
* CC=clang cmake -B build-clang
* cmake --build build-clang --target fuzzpuzz-libfuzzer
* mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
* build-clang/fuzzpuzz-libfuzzer -fork=1 -ignore_crashes=1 \
* -dict=fuzzpuzz.dict fuzz-corpus
*/ */
#include <stdbool.h> #include <stdbool.h>
@ -85,28 +94,15 @@ static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx,
return NULL; return NULL;
} }
static bool savefile_read(void *wctx, void *buf, int len) #if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER) || \
{ !defined(OMIT_MAIN)
FILE *fp = (FILE *)wctx;
int ret;
ret = fread(buf, 1, len, fp);
return (ret == len);
}
static void savefile_rewind(void *wctx)
{
FILE *fp = (FILE *)wctx;
rewind(fp);
}
static void savefile_write(void *wctx, const void *buf, int len) static void savefile_write(void *wctx, const void *buf, int len)
{ {
FILE *fp = (FILE *)wctx; FILE *fp = (FILE *)wctx;
fwrite(buf, 1, len, fp); fwrite(buf, 1, len, fp);
} }
#endif
struct memread { struct memread {
const unsigned char *buf; const unsigned char *buf;
@ -145,66 +141,110 @@ int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) {
return 0; return 0;
} }
#ifndef OMIT_MAIN #if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER)
int main(int argc, char **argv) static const char *fuzz_one_mem(unsigned char *data, size_t size) {
{ struct memread ctx;
const char *err;
int ret = -1;
FILE *in = NULL;
if (argc != 1) { ctx.buf = data;
fprintf(stderr, "usage: %s\n", argv[0]); ctx.len = size;
exit(1); ctx.pos = 0;
return fuzz_one(mem_read, &ctx, mem_rewind, savefile_write, stdout);
} }
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif #endif
#ifdef __AFL_FUZZ_TESTCASE_LEN /*
* Three different versions of main(), for standalone, AFL, and
* Honggfuzz modes. LibFuzzer brings its own main().
*/
#ifdef OMIT_MAIN
/* Nothing. */
#elif defined(__AFL_FUZZ_TESTCASE_LEN)
/* /*
* AFL persistent mode, where we fuzz from a RAM buffer provided * AFL persistent mode, where we fuzz from a RAM buffer provided
* by AFL in a loop. This version can still be run standalone if * by AFL in a loop. This version can still be run standalone if
* necessary, for instance to diagnose a crash. * necessary, for instance to diagnose a crash.
*/ */
int main(int argc, char **argv)
{
const char *err;
int ret;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
while (__AFL_LOOP(10000)) { while (__AFL_LOOP(10000)) {
if (in != NULL) fclose(in); err = fuzz_one_mem(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN);
in = fmemopen(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN, "r"); if (err != NULL) {
if (in == NULL) { fprintf(stderr, "%s\n", err);
fprintf(stderr, "fmemopen failed");
ret = 1; ret = 1;
continue; } else
ret = 0;
}
return ret;
} }
#elif defined(HAVE_HF_ITER) #elif defined(HAVE_HF_ITER)
/* /*
* Honggfuzz persistent mode. Unlike AFL persistent mode, the * Honggfuzz persistent mode. Unlike AFL persistent mode, the
* resulting executable cannot be run outside of Honggfuzz. * resulting executable cannot be run outside of Honggfuzz.
*/ */
int main(int argc, char **argv)
{
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
while (true) { while (true) {
unsigned char *testcase_buf; unsigned char *testcase_buf;
size_t testcase_len; size_t testcase_len;
if (in != NULL) fclose(in);
HF_ITER(&testcase_buf, &testcase_len); HF_ITER(&testcase_buf, &testcase_len);
in = fmemopen(testcase_buf, testcase_len, "r"); fuzz_one_mem(testcase_buf, testcase_len);
if (in == NULL) { }
fprintf(stderr, "fmemopen failed");
ret = 1;
continue;
} }
#else #else
in = stdin; /*
while (ret == -1) { * Stand-alone mode: just handle a single test case on stdin.
*/
static bool savefile_read(void *wctx, void *buf, int len)
{
FILE *fp = (FILE *)wctx;
int ret;
ret = fread(buf, 1, len, fp);
return (ret == len);
}
static void savefile_rewind(void *wctx)
{
FILE *fp = (FILE *)wctx;
rewind(fp);
}
int main(int argc, char **argv)
{
const char *err;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
/* Might in theory use this mode under AFL. */
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif #endif
err = fuzz_one(savefile_read, in, savefile_rewind,
err = fuzz_one(savefile_read, stdin, savefile_rewind,
savefile_write, stdout); savefile_write, stdout);
if (err == NULL) { if (err != NULL) {
ret = 0;
} else {
fprintf(stderr, "%s\n", err); fprintf(stderr, "%s\n", err);
ret = 1; return 1;
} }
} return 0;
return ret;
} }
#endif #endif