Fix bugs in proto3 mode encoding of submessages (#256)
[apps/agl-service-can-low-level.git] / tests / fuzztest / generate_message.c
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. */
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. */
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  */
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
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
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