shithub: puzzles

Download patch

ref: 311d227ba6d101cc2c3096eefd4bc795f98303da
parent: 69924f376bd58932c7c3aa3234b9f12eb1866edc
author: Ben Harris <bjh21@bjh21.me.uk>
date: Thu Jan 12 05:12:26 EST 2023

Merge the two versions of fuzzpuzz back together

Now there's a single version of the main loop that runs once in normal
mode and repeatedly in AFL++ persistent mode.  In persistent mode,
fmemopen() allows the loop to read the shared-memory buffer as though
it were a stdio stream.  fmemopen() is POSIX-only, but so is AFL++.

--- a/fuzzpuzz.c
+++ b/fuzzpuzz.c
@@ -13,78 +13,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef __AFL_FUZZ_TESTCASE_LEN
+# include <unistd.h> /* read() is used by __AFL_FUZZ_TESTCASE_LEN. */
+#endif
 
 #include "puzzles.h"
 
-#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.
- */
-#include <unistd.h>
-
+#ifdef __AFL_FUZZ_INIT
 __AFL_FUZZ_INIT();
-
-struct memfile {
-    unsigned char *buf;
-    int off;
-    int len;
-};
-
-static bool memfile_read(void *wctx, void *buf, int len)
-{
-    struct memfile *mem = (struct memfile *)wctx;
-
-    if (mem->len - mem->off < len) return false;
-    memcpy(buf, mem->buf + mem->off, min(len, mem->len - mem->off));
-    mem->off += len;
-    return true;
-}
-
-int main(int argc, char **argv)
-{
-    const char *err;
-    char *gamename;
-    int i;
-    const game * ourgame = NULL;
-    midend *me;
-    struct memfile mem;
-
-#ifdef __AFL_HAVE_MANUAL_CONTROL
-    __AFL_INIT();
 #endif
 
-    mem.buf = __AFL_FUZZ_TESTCASE_BUF;
-    while (__AFL_LOOP(10000)) {
-
-        mem.off = 0;
-        mem.len = __AFL_FUZZ_TESTCASE_LEN;
-
-        err = identify_game(&gamename, memfile_read, &mem);
-        if (err != NULL) continue;
-
-        for (i = 0; i < gamecount; i++)
-            if (strcmp(gamename, gamelist[i]->name) == 0)
-                ourgame = gamelist[i];
-        if (ourgame == NULL) continue;
-
-        me = midend_new(NULL, ourgame, NULL, NULL);
-
-        mem.off = 0;
-
-        err = midend_deserialise(me, memfile_read, &mem);
-        midend_free(me);
-    }
-    return 0;
-}
-
-#else
-
-/*
- * Standard mode, where we process a single save file from stdin.
- */
-
 static bool savefile_read(void *wctx, void *buf, int len)
 {
     FILE *fp = (FILE *)wctx;
@@ -98,9 +36,10 @@
 {
     const char *err;
     char *gamename;
-    int i;
-    const game * ourgame = NULL;
+    int i, ret = -1;
+    const game *ourgame = NULL;
     midend *me;
+    FILE *in = NULL;
 
     if (argc != 1) {
         fprintf(stderr, "usage: %s\n", argv[0]);
@@ -107,30 +46,56 @@
         exit(1);
     }
 
-    err = identify_game(&gamename, savefile_read, stdin);
-    if (err != NULL) {
-        fprintf(stderr, "%s\n", err);
-        exit(1);
-    }
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+    __AFL_INIT();
+#endif
 
-    for (i = 0; i < gamecount; i++)
-        if (strcmp(gamename, gamelist[i]->name) == 0)
-            ourgame = gamelist[i];
-    if (ourgame == NULL) {
-        fprintf(stderr, "Game '%s' not recognised\n", gamename);
-        exit(1);
-    }
+#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.
+     */
 
-    me = midend_new(NULL, ourgame, NULL, NULL);
+    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");
+            ret = 1;
+            continue;
+        }
+#else
+    in = stdin;
+    while (ret == -1) {
+#endif
+        err = identify_game(&gamename, savefile_read, in);
+        if (err != NULL) {
+            fprintf(stderr, "%s\n", err);
+            ret = 1;
+            continue;
+        }
 
-    rewind(stdin);
-    err = midend_deserialise(me, savefile_read, stdin);
-    if (err != NULL) {
-        fprintf(stderr, "%s\n", err);
-        exit(1);
+        for (i = 0; i < gamecount; i++)
+            if (strcmp(gamename, gamelist[i]->name) == 0)
+                ourgame = gamelist[i];
+        if (ourgame == NULL) {
+            fprintf(stderr, "Game '%s' not recognised\n", gamename);
+            ret = 1;
+            continue;
+        }
+
+        me = midend_new(NULL, ourgame, NULL, NULL);
+
+        rewind(in);
+        err = midend_deserialise(me, savefile_read, in);
+        if (err != NULL) {
+            fprintf(stderr, "%s\n", err);
+            ret = 1;
+            continue;
+        }
+        midend_free(me);
+        ret = 0;
     }
-    midend_free(me);
-    return 0;
+    return ret;
 }
-
-#endif