shithub: puzzles

Download patch

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