diff options
Diffstat (limited to 'apps/plugins/puzzles/src/fuzzpuzz.c')
-rw-r--r-- | apps/plugins/puzzles/src/fuzzpuzz.c | 250 |
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 | ||
52 | extern int HF_ITER(unsigned char **, size_t *); | ||
53 | #endif | ||
54 | |||
55 | /* This function is expected by libFuzzer. */ | ||
56 | |||
57 | int LLVMFuzzerTestOneInput(unsigned char *data, size_t size); | ||
58 | |||
59 | static 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) | ||
99 | static 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 | |||
107 | struct memread { | ||
108 | const unsigned char *buf; | ||
109 | size_t pos; | ||
110 | size_t len; | ||
111 | }; | ||
112 | |||
113 | static 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 | |||
123 | static void mem_rewind(void *wctx) | ||
124 | { | ||
125 | struct memread *ctx = wctx; | ||
126 | |||
127 | ctx->pos = 0; | ||
128 | } | ||
129 | |||
130 | static void null_write(void *wctx, const void *buf, int len) | ||
131 | { | ||
132 | } | ||
133 | |||
134 | int 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) | ||
145 | static 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 | */ | ||
168 | int 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 | */ | ||
195 | int 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 | */ | ||
212 | static 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 | |||
221 | static void savefile_rewind(void *wctx) | ||
222 | { | ||
223 | FILE *fp = (FILE *)wctx; | ||
224 | |||
225 | rewind(fp); | ||
226 | } | ||
227 | |||
228 | int 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 | ||