/src/dovecot/src/lib-json/fuzz-istream-json-string.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "istream.h" |
6 | | #include "istream-private.h" |
7 | | #include "test-common.h" |
8 | | #include "fuzzer.h" |
9 | | |
10 | | #include "istream-json-string.h" |
11 | | |
12 | | /* |
13 | | * Feed arbitrary bytes into i_stream_create_json_string() and: |
14 | | * 1. Drain the decoded output completely. |
15 | | * 2. If the stream is seekable, seek back to 0 and drain again, |
16 | | * verifying both reads produce identical output. |
17 | | */ |
18 | 1.96k | FUZZ_BEGIN_DATA(const unsigned char *data, size_t size) |
19 | 1.96k | { |
20 | 1.96k | struct istream *raw, *jstr; |
21 | 1.96k | const unsigned char *buf; |
22 | 1.96k | size_t buf_size; |
23 | 1.96k | string_t *first, *second; |
24 | 1.96k | ssize_t ret; |
25 | | |
26 | 1.96k | raw = i_stream_create_from_data(data, size); |
27 | 1.96k | jstr = i_stream_create_json_string(raw); |
28 | 1.96k | i_stream_unref(&raw); |
29 | | |
30 | | /* First pass: decode everything */ |
31 | 1.96k | first = str_new(default_pool, 64); |
32 | 7.09k | while ((ret = i_stream_read_more(jstr, &buf, &buf_size)) > 0) { |
33 | 6.11k | str_append_data(first, buf, buf_size); |
34 | 6.11k | i_stream_skip(jstr, buf_size); |
35 | 6.11k | } |
36 | | /* ret == -1 on EOF or error; either is acceptable for fuzz input */ |
37 | | |
38 | | /* Second pass: seek back and verify output is identical. |
39 | | Only meaningful when the first pass completed without error; |
40 | | i_stream_seek() is a no-op when stream_errno != 0. */ |
41 | 1.96k | if (jstr->seekable && jstr->stream_errno == 0) { |
42 | 571 | i_stream_seek(jstr, 0); |
43 | | |
44 | 571 | second = str_new(default_pool, 64); |
45 | 6.53k | while ((ret = i_stream_read_more(jstr, &buf, &buf_size)) > 0) { |
46 | 5.96k | str_append_data(second, buf, buf_size); |
47 | 5.96k | i_stream_skip(jstr, buf_size); |
48 | 5.96k | } |
49 | | |
50 | | /* Both reads must produce the same bytes */ |
51 | 571 | i_assert(str_len(first) == str_len(second) && |
52 | 571 | memcmp(str_data(first), str_data(second), |
53 | 571 | str_len(first)) == 0); |
54 | 571 | str_free(&second); |
55 | 571 | } |
56 | | |
57 | 981 | str_free(&first); |
58 | 981 | i_stream_unref(&jstr); |
59 | 981 | } |
60 | 981 | FUZZ_END |