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