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 "alltypes_static.pb.h"
12 #include "random_data.h"
13 
14 #ifndef FUZZTEST_BUFSIZE
15 #define FUZZTEST_BUFSIZE 4096
16 #endif
17 
18 /* Check that size/count fields do not exceed their max size.
19  * Otherwise we would have to loop pretty long in generate_message().
20  * Note that there may still be a few encoding errors from submessages.
21  */
limit_sizes(alltypes_static_AllTypes * msg)22 static void limit_sizes(alltypes_static_AllTypes *msg)
23 {
24     pb_field_iter_t iter;
25     pb_field_iter_begin(&iter, alltypes_static_AllTypes_fields, msg);
26     while (pb_field_iter_next(&iter))
27     {
28         if (PB_LTYPE(iter.type) == PB_LTYPE_BYTES)
29         {
30             ((pb_bytes_array_t*)iter.pData)->size %= iter.data_size - PB_BYTES_ARRAY_T_ALLOCSIZE(0);
31         }
32 
33         if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED)
34         {
35             *((pb_size_t*)iter.pSize) %= iter.array_size;
36         }
37 
38         if (PB_HTYPE(iter.type) == PB_HTYPE_ONEOF)
39         {
40             /* Set the oneof to this message type with 50% chance. */
41             if (rand_word() & 1)
42             {
43                 *((pb_size_t*)iter.pSize) = iter.tag;
44             }
45         }
46     }
47 }
48 
generate_message()49 static void generate_message()
50 {
51     alltypes_static_AllTypes msg;
52     alltypes_static_TestExtension extmsg = alltypes_static_TestExtension_init_zero;
53     pb_extension_t ext = pb_extension_init_zero;
54 
55     static uint8_t buf[FUZZTEST_BUFSIZE];
56     pb_ostream_t stream = {0};
57 
58     do {
59         rand_fill((void*)&msg, sizeof(msg));
60         limit_sizes(&msg);
61 
62         rand_fill((void*)&extmsg, sizeof(extmsg));
63         ext.type = &alltypes_static_TestExtension_testextension;
64         ext.dest = &extmsg;
65         ext.next = NULL;
66         msg.extensions = &ext;
67 
68         stream = pb_ostream_from_buffer(buf, sizeof(buf));
69     } while (!pb_encode(&stream, alltypes_static_AllTypes_fields, &msg));
70 
71     fwrite(buf, 1, stream.bytes_written, stdout);
72 }
73 
main(int argc,char ** argv)74 int main(int argc, char **argv)
75 {
76     if (argc < 2)
77     {
78         fprintf(stderr, "Usage: generate_message <seed>\n");
79         return 1;
80     }
81 
82     random_set_seed(atol(argv[1]));
83 
84     generate_message();
85 
86     return 0;
87 }
88 
89