ref: 53a1faa0d758c86c5bc77808c4265129d627be1b
parent: 9478efe32ea5aa6577d11fe45df81b49199780cd
author: Ben Harris <bjh21@bjh21.me.uk>
date: Sat Jan 7 13:57:48 EST 2023
Add a fuzzing harness for Puzzles This just feeds save files into the loading code, but because of how Puzzles is structured that actually exercises most of its parsers.
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -275,4 +275,9 @@
cliprogram(sort-test sort.c COMPILE_DEFINITIONS SORT_TEST)
cliprogram(tree234-test tree234.c COMPILE_DEFINITIONS TEST)
+write_generated_games_header()
+cliprogram(fuzzpuzz fuzzpuzz.c list.c ${puzzle_sources}
+ COMPILE_DEFINITIONS COMBINED)
+target_include_directories(fuzzpuzz PRIVATE ${generated_include_dir})
+
build_extras()
--- /dev/null
+++ b/fuzzpuzz.c
@@ -1,0 +1,65 @@
+/*
+ * fuzzpuzz.c: Fuzzing frontend to all puzzles.
+ */
+
+/*
+ * The idea here is that this front-end supports all back-ends and can
+ * feed them save files. This tests the deserialiser, the code for
+ * loading game descriptions, and the processing of move strings,
+ * without all the tedium of actually rendering anything.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "puzzles.h"
+
+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);
+}
+
+int main(int argc, char **argv)
+{
+ const char *err;
+ char *gamename;
+ int i;
+ const game * ourgame = NULL;
+ midend *me;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(1);
+ }
+
+ err = identify_game(&gamename, 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);
+ exit(1);
+ }
+
+ me = midend_new(NULL, ourgame, NULL, NULL);
+
+ rewind(stdin);
+ err = midend_deserialise(me, savefile_read, stdin);
+ if (err != NULL) {
+ fprintf(stderr, "%s\n", err);
+ exit(1);
+ }
+ midend_free(me);
+ return 0;
+}