1 /* Generates a random, valid protobuf message. Useful to seed
2 * external fuzzers such as afl-fuzz.
3 */
4
5 #include <pb_encode.h>
6 #include <pb_common.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <time.h>
12 #include "alltypes_static.pb.h"
13
14 static uint64_t random_seed;
15
16 /* Uses xorshift64 here instead of rand() for both speed and
17 * reproducibility across platforms. */
rand_word()18 static uint32_t rand_word()
19 {
20 random_seed ^= random_seed >> 12;
21 random_seed ^= random_seed << 25;
22 random_seed ^= random_seed >> 27;
23 return random_seed * 2685821657736338717ULL;
24 }
25
26 /* Fills a buffer with random data. */
rand_fill(uint8_t * buf,size_t count)27 static void rand_fill(uint8_t *buf, size_t count)
28 {
29 while (count--)
30 {
31 *buf++ = rand_word() & 0xff;
32 }
33 }
34
35 /* Check that size/count fields do not exceed their max size.
36 * Otherwise we would have to loop pretty long in generate_message().
37 * Note that there may still be a few encoding errors from submessages.
38 */
limit_sizes(alltypes_static_AllTypes * msg)39 static void limit_sizes(alltypes_static_AllTypes *msg)
40 {
41 pb_field_iter_t iter;
42 pb_field_iter_begin(&iter, alltypes_static_AllTypes_fields, msg);
43 while (pb_field_iter_next(&iter))
44 {
45 if (PB_LTYPE(iter.pos->type) == PB_LTYPE_BYTES)
46 {
47 ((pb_bytes_array_t*)iter.pData)->size %= iter.pos->data_size - PB_BYTES_ARRAY_T_ALLOCSIZE(0);
48 }
49
50 if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED)
51 {
52 *((pb_size_t*)iter.pSize) %= iter.pos->array_size;
53 }
54
55 if (PB_HTYPE(iter.pos->type) == PB_HTYPE_ONEOF)
56 {
57 /* Set the oneof to this message type with 50% chance. */
58 if (rand_word() & 1)
59 {
60 *((pb_size_t*)iter.pSize) = iter.pos->tag;
61 }
62 }
63 }
64 }
65
generate_message()66 static void generate_message()
67 {
68 alltypes_static_AllTypes msg;
69 uint8_t buf[8192];
70 pb_ostream_t stream = {0};
71
72 do {
73 if (stream.errmsg)
74 fprintf(stderr, "Encoder error: %s\n", stream.errmsg);
75
76 stream = pb_ostream_from_buffer(buf, sizeof(buf));
77 rand_fill((void*)&msg, sizeof(msg));
78 limit_sizes(&msg);
79 } while (!pb_encode(&stream, alltypes_static_AllTypes_fields, &msg));
80
81 fwrite(buf, 1, stream.bytes_written, stdout);
82 }
83
main(int argc,char ** argv)84 int main(int argc, char **argv)
85 {
86 if (argc > 1)
87 {
88 random_seed = atol(argv[1]);
89 }
90 else
91 {
92 random_seed = time(NULL);
93 }
94
95 fprintf(stderr, "Random seed: %llu\n", (long long unsigned)random_seed);
96
97 generate_message();
98
99 return 0;
100 }
101
102