1 /* Fuzz testing for the nanopb core. 2 * This can be used with external fuzzers, e.g. radamsa. 3 * It performs most of the same checks as fuzztest, but does not feature data generation. 4 */ 5 6 #include <pb_decode.h> 7 #include <pb_encode.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <assert.h> 12 #include <time.h> 13 #include <malloc_wrappers.h> 14 #include "alltypes_static.pb.h" 15 #include "alltypes_pointer.pb.h" 16 17 #define BUFSIZE 4096 18 19 static bool do_static_decode(uint8_t *buffer, size_t msglen, bool assert_success) 20 { 21 pb_istream_t stream; 22 bool status; 23 24 alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes)); 25 stream = pb_istream_from_buffer(buffer, msglen); 26 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg); 27 28 if (!status && assert_success) 29 { 30 /* Anything that was successfully encoded, should be decodeable. 31 * One exception: strings without null terminator are encoded up 32 * to end of buffer, but refused on decode because the terminator 33 * would not fit. */ 34 if (strcmp(stream.errmsg, "string overflow") != 0) 35 assert(status); 36 } 37 38 free_with_check(msg); 39 return status; 40 } 41 42 static bool do_pointer_decode(uint8_t *buffer, size_t msglen, bool assert_success) 43 { 44 pb_istream_t stream; 45 bool status; 46 alltypes_pointer_AllTypes *msg; 47 48 msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); 49 memset(msg, 0, sizeof(alltypes_pointer_AllTypes)); 50 stream = pb_istream_from_buffer(buffer, msglen); 51 52 assert(get_alloc_count() == 0); 53 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg); 54 55 if (assert_success) 56 assert(status); 57 58 pb_release(alltypes_pointer_AllTypes_fields, msg); 59 assert(get_alloc_count() == 0); 60 61 free_with_check(msg); 62 63 return status; 64 } 65 66 /* Do a decode -> encode -> decode -> encode roundtrip */ 67 static void do_static_roundtrip(uint8_t *buffer, size_t msglen) 68 { 69 bool status; 70 uint8_t *buf2 = malloc_with_check(BUFSIZE); 71 uint8_t *buf3 = malloc_with_check(BUFSIZE); 72 size_t msglen2, msglen3; 73 alltypes_static_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_static_AllTypes)); 74 alltypes_static_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_static_AllTypes)); 75 memset(msg1, 0, sizeof(alltypes_static_AllTypes)); 76 memset(msg2, 0, sizeof(alltypes_static_AllTypes)); 77 78 { 79 pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); 80 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg1); 81 assert(status); 82 } 83 84 { 85 pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE); 86 status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg1); 87 assert(status); 88 msglen2 = stream.bytes_written; 89 } 90 91 { 92 pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); 93 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg2); 94 assert(status); 95 } 96 97 { 98 pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE); 99 status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg2); 100 assert(status); 101 msglen3 = stream.bytes_written; 102 } 103 104 assert(msglen2 == msglen3); 105 assert(memcmp(buf2, buf3, msglen2) == 0); 106 107 free_with_check(msg1); 108 free_with_check(msg2); 109 free_with_check(buf2); 110 free_with_check(buf3); 111 } 112 113 /* Do decode -> encode -> decode -> encode roundtrip */ 114 static void do_pointer_roundtrip(uint8_t *buffer, size_t msglen) 115 { 116 bool status; 117 uint8_t *buf2 = malloc_with_check(BUFSIZE); 118 uint8_t *buf3 = malloc_with_check(BUFSIZE); 119 size_t msglen2, msglen3; 120 alltypes_pointer_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); 121 alltypes_pointer_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); 122 memset(msg1, 0, sizeof(alltypes_pointer_AllTypes)); 123 memset(msg2, 0, sizeof(alltypes_pointer_AllTypes)); 124 125 { 126 pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); 127 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg1); 128 assert(status); 129 } 130 131 { 132 pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE); 133 status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg1); 134 assert(status); 135 msglen2 = stream.bytes_written; 136 } 137 138 { 139 pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); 140 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg2); 141 assert(status); 142 } 143 144 { 145 pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE); 146 status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg2); 147 assert(status); 148 msglen3 = stream.bytes_written; 149 } 150 151 assert(msglen2 == msglen3); 152 assert(memcmp(buf2, buf3, msglen2) == 0); 153 154 pb_release(alltypes_pointer_AllTypes_fields, msg1); 155 pb_release(alltypes_pointer_AllTypes_fields, msg2); 156 free_with_check(msg1); 157 free_with_check(msg2); 158 free_with_check(buf2); 159 free_with_check(buf3); 160 } 161 162 static void run_iteration() 163 { 164 uint8_t *buffer = malloc_with_check(BUFSIZE); 165 size_t msglen; 166 bool status; 167 168 msglen = fread(buffer, 1, BUFSIZE, stdin); 169 170 status = do_static_decode(buffer, msglen, false); 171 172 if (status) 173 do_static_roundtrip(buffer, msglen); 174 175 status = do_pointer_decode(buffer, msglen, false); 176 177 if (status) 178 do_pointer_roundtrip(buffer, msglen); 179 180 free_with_check(buffer); 181 } 182 183 int main(int argc, char **argv) 184 { 185 run_iteration(); 186 187 return 0; 188 } 189 190