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 102