ref: 80de73a6aa4c4e726860c492d2264d4958a56b0d
parent: 5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4
author: Ben Harris <bjh21@bjh21.me.uk>
date: Mon Feb 20 17:53:33 EST 2023
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.
--- a/fuzzpuzz.c
+++ b/fuzzpuzz.c
@@ -23,6 +23,15 @@
* cmake --build build-honggfuzz --target fuzzpuzz
* mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
* 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>
@@ -85,22 +94,8 @@
return NULL;
}
-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);
-}
-
+#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER) || \
+ !defined(OMIT_MAIN)
static void savefile_write(void *wctx, const void *buf, int len)
{
FILE *fp = (FILE *)wctx;
@@ -107,6 +102,7 @@
fwrite(buf, 1, len, fp);
}
+#endif
struct memread {
const unsigned char *buf;
@@ -145,66 +141,110 @@
return 0;
}
-#ifndef OMIT_MAIN
+#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER)
+static const char *fuzz_one_mem(unsigned char *data, size_t size) {
+ struct memread ctx;
+
+ ctx.buf = data;
+ ctx.len = size;
+ ctx.pos = 0;
+ return fuzz_one(mem_read, &ctx, mem_rewind, savefile_write, stdout);
+}
+#endif
+
+/*
+ * 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
+ * by AFL in a loop. This version can still be run standalone if
+ * necessary, for instance to diagnose a crash.
+ */
int main(int argc, char **argv)
{
const char *err;
- int ret = -1;
- FILE *in = NULL;
+ int ret;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
- exit(1);
+ return 1;
}
-
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
-
-#ifdef __AFL_FUZZ_TESTCASE_LEN
- /*
- * AFL persistent mode, where we fuzz from a RAM buffer provided
- * by AFL in a loop. This version can still be run standalone if
- * necessary, for instance to diagnose a crash.
- */
-
while (__AFL_LOOP(10000)) {
- if (in != NULL) fclose(in);
- in = fmemopen(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN, "r");
- if (in == NULL) {
- fprintf(stderr, "fmemopen failed");
+ err = fuzz_one_mem(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN);
+ if (err != NULL) {
+ fprintf(stderr, "%s\n", err);
ret = 1;
- continue;
- }
+ } else
+ ret = 0;
+ }
+ return ret;
+}
#elif defined(HAVE_HF_ITER)
- /*
- * Honggfuzz persistent mode. Unlike AFL persistent mode, the
- * resulting executable cannot be run outside of Honggfuzz.
- */
+/*
+ * Honggfuzz persistent mode. Unlike AFL persistent mode, the
+ * 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) {
unsigned char *testcase_buf;
size_t testcase_len;
- if (in != NULL) fclose(in);
HF_ITER(&testcase_buf, &testcase_len);
- in = fmemopen(testcase_buf, testcase_len, "r");
- if (in == NULL) {
- fprintf(stderr, "fmemopen failed");
- ret = 1;
- continue;
- }
+ fuzz_one_mem(testcase_buf, testcase_len);
+ }
+}
#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
- err = fuzz_one(savefile_read, in, savefile_rewind,
- savefile_write, stdout);
- if (err == NULL) {
- ret = 0;
- } else {
- fprintf(stderr, "%s\n", err);
- ret = 1;
- }
+
+ err = fuzz_one(savefile_read, stdin, savefile_rewind,
+ savefile_write, stdout);
+ if (err != NULL) {
+ fprintf(stderr, "%s\n", err);
+ return 1;
}
- return ret;
+ return 0;
}
#endif