summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/fuzzpuzz.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/fuzzpuzz.c')
-rw-r--r--apps/plugins/puzzles/src/fuzzpuzz.c250
1 files changed, 0 insertions, 250 deletions
diff --git a/apps/plugins/puzzles/src/fuzzpuzz.c b/apps/plugins/puzzles/src/fuzzpuzz.c
deleted file mode 100644
index 3fb632ec57..0000000000
--- a/apps/plugins/puzzles/src/fuzzpuzz.c
+++ /dev/null
@@ -1,250 +0,0 @@
1/*
2 * fuzzpuzz.c: Fuzzing frontend to all puzzles.
3 */
4
5/*
6 * The idea here is that this front-end supports all back-ends and can
7 * feed them save files. It then asks the back-end to draw the puzzle
8 * (through a null drawing API) and reserialises the state. This
9 * tests the deserialiser, the code for loading game descriptions, the
10 * processing of move strings, the redraw code, and the serialisation
11 * routines, but is still pretty quick.
12 *
13 * To use AFL++ to drive fuzzpuzz, you can do something like:
14 *
15 * CC=afl-cc cmake -B build-afl
16 * cmake --build build-afl --target fuzzpuzz
17 * mkdir fuzz-in && ln icons/''*.sav fuzz-in
18 * afl-fuzz -i fuzz-in -o fuzz-out -x fuzzpuzz.dict -- build-afl/fuzzpuzz
19 *
20 * Similarly with Honggfuzz:
21 *
22 * CC=hfuzz-cc cmake -B build-honggfuzz
23 * cmake --build build-honggfuzz --target fuzzpuzz
24 * mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
25 * honggfuzz -s -i fuzz-corpus -w fuzzpuzz.dict -- build-honggfuzz/fuzzpuzz
26 *
27 * You can also use libFuzzer, though it's not really a good fit for
28 * Puzzles. The experimental forking mode seems to work OK:
29 *
30 * CC=clang cmake -B build-clang -DWITH_LIBFUZZER=Y
31 * cmake --build build-clang --target fuzzpuzz
32 * mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
33 * build-clang/fuzzpuzz -fork=1 -ignore_crashes=1 -dict=fuzzpuzz.dict \
34 * fuzz-corpus
35 */
36
37#include <stdbool.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#ifdef __AFL_FUZZ_TESTCASE_LEN
42# include <unistd.h> /* read() is used by __AFL_FUZZ_TESTCASE_LEN. */
43#endif
44
45#include "puzzles.h"
46
47#ifdef __AFL_FUZZ_INIT
48__AFL_FUZZ_INIT();
49#endif
50
51#ifdef HAVE_HF_ITER
52extern int HF_ITER(unsigned char **, size_t *);
53#endif
54
55/* This function is expected by libFuzzer. */
56
57int LLVMFuzzerTestOneInput(unsigned char *data, size_t size);
58
59static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx,
60 void (*rewindfn)(void *),
61 void (*writefn)(void *, const void *, int),
62 void *wctx)
63{
64 const char *err;
65 char *gamename;
66 int i, w, h;
67 const game *ourgame = NULL;
68 static const drawing_api drapi = { NULL };
69 midend *me;
70
71 err = identify_game(&gamename, readfn, rctx);
72 if (err != NULL) return err;
73
74 for (i = 0; i < gamecount; i++)
75 if (strcmp(gamename, gamelist[i]->name) == 0)
76 ourgame = gamelist[i];
77 sfree(gamename);
78 if (ourgame == NULL)
79 return "Game not recognised";
80
81 me = midend_new(NULL, ourgame, &drapi, NULL);
82
83 rewindfn(rctx);
84 err = midend_deserialise(me, readfn, rctx);
85 if (err != NULL) {
86 midend_free(me);
87 return err;
88 }
89 w = h = INT_MAX;
90 midend_size(me, &w, &h, false, 1);
91 midend_redraw(me);
92 midend_serialise(me, writefn, wctx);
93 midend_free(me);
94 return NULL;
95}
96
97#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER) || \
98 !defined(OMIT_MAIN)
99static void savefile_write(void *wctx, const void *buf, int len)
100{
101 FILE *fp = (FILE *)wctx;
102
103 fwrite(buf, 1, len, fp);
104}
105#endif
106
107struct memread {
108 const unsigned char *buf;
109 size_t pos;
110 size_t len;
111};
112
113static bool mem_read(void *wctx, void *buf, int len)
114{
115 struct memread *ctx = wctx;
116
117 if (ctx->pos + len > ctx->len) return false;
118 memcpy(buf, ctx->buf + ctx->pos, len);
119 ctx->pos += len;
120 return true;
121}
122
123static void mem_rewind(void *wctx)
124{
125 struct memread *ctx = wctx;
126
127 ctx->pos = 0;
128}
129
130static void null_write(void *wctx, const void *buf, int len)
131{
132}
133
134int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) {
135 struct memread ctx;
136
137 ctx.buf = data;
138 ctx.len = size;
139 ctx.pos = 0;
140 fuzz_one(mem_read, &ctx, mem_rewind, null_write, NULL);
141 return 0;
142}
143
144#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER)
145static const char *fuzz_one_mem(unsigned char *data, size_t size) {
146 struct memread ctx;
147
148 ctx.buf = data;
149 ctx.len = size;
150 ctx.pos = 0;
151 return fuzz_one(mem_read, &ctx, mem_rewind, savefile_write, stdout);
152}
153#endif
154
155/*
156 * Three different versions of main(), for standalone, AFL, and
157 * Honggfuzz modes. LibFuzzer brings its own main().
158 */
159
160#ifdef OMIT_MAIN
161/* Nothing. */
162#elif defined(__AFL_FUZZ_TESTCASE_LEN)
163/*
164 * AFL persistent mode, where we fuzz from a RAM buffer provided
165 * by AFL in a loop. This version can still be run standalone if
166 * necessary, for instance to diagnose a crash.
167 */
168int main(int argc, char **argv)
169{
170 const char *err;
171 int ret;
172
173 if (argc != 1) {
174 fprintf(stderr, "usage: %s\n", argv[0]);
175 return 1;
176 }
177#ifdef __AFL_HAVE_MANUAL_CONTROL
178 __AFL_INIT();
179#endif
180 while (__AFL_LOOP(10000)) {
181 err = fuzz_one_mem(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN);
182 if (err != NULL) {
183 fprintf(stderr, "%s\n", err);
184 ret = 1;
185 } else
186 ret = 0;
187 }
188 return ret;
189}
190#elif defined(HAVE_HF_ITER)
191/*
192 * Honggfuzz persistent mode. Unlike AFL persistent mode, the
193 * resulting executable cannot be run outside of Honggfuzz.
194 */
195int main(int argc, char **argv)
196{
197 if (argc != 1) {
198 fprintf(stderr, "usage: %s\n", argv[0]);
199 return 1;
200 }
201 while (true) {
202 unsigned char *testcase_buf;
203 size_t testcase_len;
204 HF_ITER(&testcase_buf, &testcase_len);
205 fuzz_one_mem(testcase_buf, testcase_len);
206 }
207}
208#else
209/*
210 * Stand-alone mode: just handle a single test case on stdin.
211 */
212static bool savefile_read(void *wctx, void *buf, int len)
213{
214 FILE *fp = (FILE *)wctx;
215 int ret;
216
217 ret = fread(buf, 1, len, fp);
218 return (ret == len);
219}
220
221static void savefile_rewind(void *wctx)
222{
223 FILE *fp = (FILE *)wctx;
224
225 rewind(fp);
226}
227
228int main(int argc, char **argv)
229{
230 const char *err;
231
232 if (argc != 1) {
233 fprintf(stderr, "usage: %s\n", argv[0]);
234 return 1;
235 }
236
237 /* Might in theory use this mode under AFL. */
238#ifdef __AFL_HAVE_MANUAL_CONTROL
239 __AFL_INIT();
240#endif
241
242 err = fuzz_one(savefile_read, stdin, savefile_rewind,
243 savefile_write, stdout);
244 if (err != NULL) {
245 fprintf(stderr, "%s\n", err);
246 return 1;
247 }
248 return 0;
249}
250#endif